[{"content":"Receber uma proposta para uma vaga de Kotlin sempre traz a mesma pergunta: CLT ou PJ? O valor bruto da PJ costuma chamar atenção, mas ele esconde o custo das férias, do 13º, do FGTS, do plano de saúde e dos impostos que passam a ser por sua conta. Em 2026, com o mercado brasileiro de Android e backend Kotlin aquecido, entender essa diferença é o que separa um bom acordo de uma armadilha financeira.\nEste guia compara os dois regimes na prática: o que cada um garante, quanto sobra de verdade no bolso e em quais situações um costuma valer mais que o outro. As faixas salariais abaixo são consistentes com os salários de desenvolvedor Kotlin no Brasil detalhados em páginas dedicadas por nível.\nO que é CLT e o que é PJ, em uma frase Na CLT (Consolidação das Leis do Trabalho), você é empregado registrado da empresa. Há carteira assinada, jornada definida, direitos trabalhistas e uma série de obrigações para o empregador — o que explica por que o custo total de um profissional CLT é bem maior que o salário bruto.\nNa PJ, você é uma empresa (pessoa jurídica) prestando um serviço. A relação é comercial, regida por contrato e nota fiscal, não pela CLT. Não há férias, 13º, FGTS ou estabilidade — e o imposto sobre o faturamento corre por sua conta.\nFaixas de salário Kotlin em 2026: CLT x PJ Os valores abaixo refletem o mercado brasileiro em 2026 e são um bom ponto de partida para comparar propostas.\nNível CLT (mensal) PJ (mensal) Remoto internacional Júnior (0–2 anos) R$ 3.500 – R$ 6.500 R$ 5.000 – R$ 8.500 USD 2.000 – USD 4.000 Pleno (2–5 anos) R$ 6.500 – R$ 12.000 R$ 9.000 – R$ 16.000 USD 3.500 – USD 7.000 Sênior (5+ anos) R$ 12.000 – R$ 22.000 R$ 16.000 – R$ 30.000 USD 6.000 – USD 12.000 Para os números detalhados por região, stack e tipo de empresa, consulte as páginas específicas de salário Kotlin júnior, salário Kotlin pleno, salário Kotlin sênior, além das páginas dedicadas a desenvolvedor Android Kotlin e desenvolvedor backend Kotlin. Note que a PJ aparece mais alta na tabela, mas isso não significa que sobre mais — é a próxima conta que decide.\nO que a CLT garante (e que a PJ não dá) O custo escondido da CLT é exatamente o seu valor. Além do salário bruto, a empresa paga e/ou provê:\n13º salário: um salário extra por ano, pago em duas parcelas. Férias remuneradas com acréscimo de 1/3 constitucional: 30 dias de folga pagos com bônus. FGTS: depósito de 8% ao mês sobre o salário em uma conta vinculada que é sua, mais multa de 40% sobre o saldo em caso de demissão sem justa causa. INSS e auxílios (doença, maternidade) pagos pelo regime. Vale-transporte e, na maioria das empresas de tecnologia, vale-refeição ou vale-alimentação. Plano de saúde e odontológico com custo compartilhado ou integralmente pagos pela empresa. PLR (Participação nos Lucros e Resultados), comum em bancos, fintechs e grandes empresas de tecnologia. Aviso prévio e proteção contra demissão arbitrária. Some férias + 1/3, 13º e FGTS e você chega facilmente a algo como três salários e meio de benefício indireto por ano. É esse o pacote que a PJ precisa cobrir.\nO que significa, de verdade, ser PJ Virar PJ é abrir mão desse pacote e assumir uma pequena operação. Os custos típicos de uma PJ de pessoa desenvolvedora incluem:\nContador: entre R$ 150 e R$ 400 por mês para emissão de guias, folha (se houver sócio) e declarações. Impostos: no Simples Nacional, serviços de tecnologia costumam cair no anexo III, IV ou V (a escolha depende do fator R e da atividade). Há ainda ISS municipal sobre o faturamento. Pró-labore e INSS: se você for sócio, precisa retirar um pró-labore e recolher INSS sobre ele. Reserva de emergência: sem FGTS e sem aviso prévio, é prudente guardar de 3 a 6 meses de custo de vida. Plano de saúde, vale-refeição e férias saem do seu bolso — quando você tira férias, ninguém te paga. A regra prática que muita gente usa: para a PJ ser equivalente à CLT, o valor bruto precisa ser cerca de 30% a 50% maior (ou, em uma fórmula rápida, algo entre 1,3x e 1,4x o salário CLT). Abaixo disso, a CLT costuma vencer.\nUm exemplo concreto para um pleno Imagine um desenvolvedor Kotlin pleno com uma proposta de R$ 9.000 CLT e outra de R$ 11.500 PJ. À primeira vista, a PJ \u0026ldquo;ganha\u0026rdquo; em R$ 2.500 por mês. Mas subtraindo contador (~R$ 300), imposto do Simples, plano de saúde que a CLT cobria (~R$ 500), e reservando férias e 13º (cerca de R$ 1.500/mês de provisão), a vantagem evapora. Aqui, com diferença de apenas ~28%, a CLT costuma ser o melhor acordo. Se a PJ fosse R$ 13.500 ou mais (acima de 1,4x), o cenário se inverte.\nMEI ou ME: qual enquadramento escolher na PJ Nem toda PJ é igual. Para quem está começando, dois caminhos aparecem:\nMEI (Microempreendedor Individual): tributação fixa e baixa, mas o faturamento anual é limitado. Para serviços, o teto histórico do MEI fica em torno de R$ 81 mil por ano (cerca de R$ 6.750 por mês) — confirme o valor vigente no Portal do Empreendedor, pois ele pode mudar. É ideal para um contrato único de valor menor, mas trava quem ganha mais. ME (Microempresa) no Simples Nacional: aceita faturamento maior e é o enquadramento mais comum para devs pleno e sênior que prestam serviço para uma ou poucas empresas. O contador define o anexo ideal. Se você já busca vagas de Kotlin como autônomo ou consultor, vale revisar também o guia sobre desenvolvedor Kotlin freelancer, que cobre precificação e gestão de contratos.\nQuando a CLT costuma valer mais A CLT tende a vencer quando:\nVocê é júnior e a prioridade é aprendizado, mentoria e estabilidade no primeiro emprego — veja o guia de estágio em Kotlin e Android. A diferença entre CLT e PJ é pequena (menos de ~30%). Benefícios fecham a conta a favor da CLT. Você valoriza plano de saúde, previsibilidade e rede de proteção (FGTS, seguro-desemprego indireto via reserva). A empresa oferece PLR robusta, comum em bancos e fintechs que usam Kotlin. Quando a PJ costuma valer mais A PJ tende a vencer quando:\nVocê é pleno ou sênior e consegue propostas com diferença de 40% ou mais sobre a CLT. Trabalha remoto para empresas estrangeiras, que pagam em dólares e não oferecem CLT brasileira de qualquer forma. Tem mais de um cliente e quer diversificar renda (reduz risco de depender de uma fonte só). Sua faixa de faturamento coloca o imposto efetivo do Simples abaixo da \u0026ldquo;carga\u0026rdquo; embutida nos encargos da CLT. Trabalho remoto internacional e a regra da Receita Um cenário cada vez mais comum para devs Kotlin sênior é prestar serviço para empresas dos Estados Unidos e Europa, recebendo em moeda estrangeira como PJ. A Lei nº 14.973/2024 (conversão da Medida Provisória nº 1.263/2024) criou uma faixa de isenção de Imposto de Renda para rendimentos recebidos do exterior por residentes fiscais no Brasil, com limite mensal reajustado anualmente (em 2024, o teto da isenção girava em torno de R$ 21,6 mil por mês).\nComo o valor é atualizado pela Receita Federal, confirme sempre o limite vigente no site do órgão antes de planejar o ano. Esse cenário costuma ser o que mais favorece a PJ entre profissionais seniores — mas exige organização tributária, contador especializado e declaração correta do imposto. Para entender onde essas vagas aparecem, consulte a lista de vagas de Kotlin remoto e o panorama do mercado de trabalho Kotlin no Brasil.\nCLT ou PJ por nível de carreira A decisão muda conforme a senioridade:\nJúnior: na dúvida, fique na CLT. A rede de proteção e o tempo para aprender Kotlin, Android ou backend compensam mais que os poucos mil reais a mais da PJ. Pleno: é onde a escolha fica mais disputada. Faça a conta dos 30%–50% e considere o custo de vida da sua cidade. Sênior: a PJ (e principalmente o remoto internacional) costuma ser vantajosa, desde que haja reserva de emergência e bom enquadramento tributário. Como decidir em 4 passos Converta tudo para base mensal: some salário + férias/12 + 13º/12 + FGTS + benefícios na CLT; subtraia contador, impostos e provisões na PJ. Aplique a regra dos 1,3x–1,4x: se a PJ não chega a pelo menos 30% acima da CLT equivalente, desconfie. Pondere risco e estilo de vida: estabilidade, plano de saúde e férias têm valor real; não são \u0026ldquo;detalhe\u0026rdquo;. Consulte um contador: tributação é individual e muda por cidade, faturamento e enquadramento. Não decida só com tabela da internet. Perguntas frequentes Dev Kotlin ganha mais em CLT ou PJ? O valor bruto da PJ é maior, mas o líquido real depende dos impostos, do contador, do plano de saúde e da provisão para férias e 13º. Em geral, a PJ só vale mais quando o valor bruto é pelo menos 30% a 50% superior ao da CLT equivalente.\nPosso ser MEI como desenvolvedor Kotlin? Sim, desde que o faturamento fique dentro do limite anual do MEI (historicamente em torno de R$ 81 mil por ano). Para contratos maiores, o enquadramento como ME no Simples Nacional costuma ser mais adequado.\nPJ tem direito a férias e 13º? Não. Na PJ a relação é comercial: sem férias remuneradas, sem 13º e sem FGTS. Por isso, parte do valor recebido precisa ser reservada para esses períodos.\nVale a pena CLT ou PJ para quem trabalha remoto para fora? Para devs Kotlin seniores que prestam serviço para empresas estrangeiras, a PJ costuma ser o caminho — inclusive com faixa de isenção de IR sobre rendimentos do exterior prevista na Lei nº 14.973/2024. A decisão depende do enquadramento tributário e do valor do contrato.\nEste conteúdo é informativo e não constitui orientação jurídica, contábil ou tributária. Faixas salariais refletem o mercado brasileiro de tecnologia em 2026 e variam por empresa, região e momento. Antes de escolher o regime, valide os valores vigentes (limites do MEI, teto da isenção de IR do exterior e alíquotas do Simples) com um contador e na Receita Federal. Para começar do zero, leia como se tornar desenvolvedor Kotlin e onde encontrar vagas de Kotlin no Brasil.\n","permalink":"https://kotlin.dev.br/carreira/clt-vs-pj-desenvolvedor-kotlin/","summary":"\u003cp\u003eReceber uma proposta para uma vaga de Kotlin sempre traz a mesma pergunta: \u003cstrong\u003eCLT ou PJ?\u003c/strong\u003e O valor bruto da PJ costuma chamar atenção, mas ele esconde o custo das férias, do 13º, do FGTS, do plano de saúde e dos impostos que passam a ser por sua conta. Em 2026, com o mercado brasileiro de Android e backend Kotlin aquecido, entender essa diferença é o que separa um bom acordo de uma armadilha financeira.\u003c/p\u003e","title":"CLT ou PJ para Desenvolvedor Kotlin em 2026: Guia de Decisão"},{"content":"Conseguir o primeiro estágio em desenvolvimento de software é uma das transições mais importantes da carreira. Em 2026, com Android ainda dominando o mercado brasileiro de mobile e Kotlin consolidada como linguagem oficial recomendada pelo Google, saber Kotlin virou um atalho real para entrar em times de produto de fintechs, marketplaces e empresas de tecnologia. Este guia mostra, de forma prática, como se posicionar, onde procurar e o que esperar de um estágio em Kotlin e Android no Brasil.\nSe você está começando do zero, vale ler primeiro o passo a passo de como se tornar desenvolvedor Kotlin e o guia de desenvolvimento Android com Kotlin. Eles cobrem a base; este artigo foca na etapa seguinte: transformar estudo em primeira oportunidade profissional.\nO cenário do estágio em Kotlin e Android no Brasil O Brasil é um dos maiores mercados de Android do mundo, e boa parte das vagas de estágio em desenvolvimento mobile no país envolve Kotlin. Bancos digitais, fintechs, empresas de delivery, varejo e healthtechs mantêm programas de estágio recorrentes, com processos seletivos que costumam abrir no primeiro semestre (para início no segundo semestre) e no segundo semestre (para início no ano seguinte).\nProgramas tradicionais, como os de grandes bancos e consultorias, geralmente exigem estar cursando ensino superior. Já programas de empresas de tecnologia e startups costumam aceitar candidatos autodidatas, alunos de cursos técnicos, de bootcamps ou pessoas em transição de carreira, desde que consigam demonstrar conhecimento prático. Esse segundo caminho é o mais comum para quem foca em Kotlin e Android: a porta de entrada costuma ser um portfólio que mostre código real, não só um diploma.\nOnde procurar vagas de estágio Existem três fontes principais, e o ideal é combinar todas:\nSites de vagas gerais (Gupy, LinkedIn, InfoJobs, 99Jobs): filtrando por \u0026ldquo;estágio\u0026rdquo; + \u0026ldquo;Android\u0026rdquo;, \u0026ldquo;mobile\u0026rdquo; ou \u0026ldquo;Kotlin\u0026rdquo;. A Gupy, em particular, concentra processos de grandes empresas brasileiras. Páginas de carreira das empresas: muitas das empresas que usam Kotlin no Brasil publicam vagas de estágio diretamente em seus sites. O iFood, por exemplo, é um dos maiores empregadores de desenvolvedores Android do país. Comunidades e indicações: grupos no Telegram e Discord de desenvolvedores Android brasileiros, além de eventos presenciais e online, costumam divulgar vagas antes mesmo de chegarem aos portais. Conhecer pessoas do meio acelera — e muito — a primeira colocação. Para uma visão mais ampla do mercado, consulte o panorama de vagas de Kotlin no Brasil e a lista de vagas de Kotlin remoto, que inclui oportunidades híbridas e em home office.\nO que as empresas pedem em um estagiário A expectativa para estágio é diferente da expectativa para um cargo pleno ou sênior. Ninguém espera que você domine arquitetura de microsserviços ou otimize rendering de listas com milhões de itens. O que costuma pesar nas avaliações:\nFundamentos sólidos de Kotlin: variáveis, funções, controle de fluxo, null safety, collections e lambdas. Saber a diferença entre val e var, entender por que o Kotlin separa tipos anuláveis (String?) de não anuláveis (String) e manipular listas com map, filter e forEach já coloca você à frente de muitos candidatos. Noções de Android com Kotlin: Activity, lifecycle básico, intents e interface. Hoje, boa parte das equipes trabalha com Jetpack Compose, então ter ao menos um app simples em Compose é um diferencial grande. Versionamento com Git: clonar, criar branch, fazer commit, abrir pull request e resolver conflitos simples. É uma habilidade que todo time usa diariamente. Iniciativa e capacidade de aprender: a maior parte do que você vai usar não está na faculdade. Conseguir estudar por conta própria, ler documentação em inglês e perguntar quando travar vale mais que memorizar sintaxe. O que costuma ser pedido como diferencial: testes unitários (mesmo que básicos, com JUnit), noções de arquitetura (MVVM é o padrão de fato no Android), familiaridade com coroutines e integração com APIs REST. Nenhum desses tópicos precisa ser profundo em estágio — apenas demonstrar que você já ouviu falar e tentou usar conta pontos.\nBolsa-auxílio: quanto ganha um estagiário em Kotlin e Android Estagiário não tem salário no modelo CLT tradicional; recebe uma bolsa-auxílio, regulamentada pela Lei do Estágio (Lei nº 11.788/2008). A lei não fixa um valor mínimo, mas garante recesso remunerado (30 dias proporcional por ano), Vale-Transporte e, quando a jornada chega a 6 horas, intervalo de alimentação. Os valores praticados pelo mercado variam conforme a região, o porte da empresa e o nível de exigência técnica:\nPequenas empresas e startups de menor porte: em geral entre R$ 1.000,00 e R$ 1.800,00 mensais. Médias e grandes empresas de tecnologia: costumam pagar entre R$ 1.800,00 e R$ 3.200,00 mensais. Grandes bancos, big techs e fintechs de ponta: podem chegar a R$ 3.000,00 a R$ 4.500,00 mensais, além de benefícios como Vale-Refeição, plano de saúde e auxílio home office. Esses números são referências de mercado para 2026, não uma garantia: a bolsa real depende da vaga, da carga horária (20h ou 30h semanais) e da cidade. Para comparar com a evolução futura, vale consultar a faixa de salário de desenvolvedor Kotlin júnior, que mostra o que esperar assim que o estágio vira efetivação.\nComo preparar currículo e portfólio O currículo de estagiário deve ser enxuto: uma página, dados de contato, formação (em curso ou concluída), links para GitHub e LinkedIn e, principalmente, projetos. Liste de dois a quatro projetos que você construiu de verdade, com uma linha explicando o que cada um faz e qual a stack usada.\nO portfólio pesa mais que o currículo. Um bom portfólio de Kotlin/Android tem:\nPelo menos um app Android funcional publicado ou com código aberto no GitHub, mesmo que simples (uma lista de tarefas, um app de clima consumindo uma API, um conversor de moedas). Código limpo, com nomes de variáveis e funções claros, sem segredos ou chaves de API commitadas. Um README.md que explique como rodar o projeto. Commits com mensagens que façam sentido — não um único commit gigante escrito \u0026ldquo;projeto final\u0026rdquo;. Complemente o estudo com projetos guiados dos tutoriais de Kotlin, que cobrem de fundamentos da linguagem até Room, Retrofit e MVVM. Ter esses padrões no GitHub mostra que você conhece o que o mercado usa.\nO processo seletivo passo a passo Embora cada empresa tenha seu próprio formato, a maioria dos processos de estágio em tecnologia segue um fluxo parecido:\nInscrição e triagem: formulário, currículo e, às vezes, um teste de lógica ou de português. Teste técnico online: geralmente lógica de programação, estrutura de dados básica e, em alguns casos, questões de Kotlin ou Android. Plataformas como HackerRank e Codility são comuns. Entrevista comportamental (RH): perguntas sobre motivação, trabalho em equipe e planos de carreira. Entrevista técnica: conversa com pessoas desenvolvedoras do time sobre seus projetos, fundamentos de Kotlin e, às vezes, um pequeno desafio ao vivo. Decisão e proposta: a empresa retorna com a oferta de bolsa-auxílio e benefícios. Para se sair bem na entrevista técnica, leia o guia de como se preparar para entrevistas de Kotlin e Android, que detalha perguntas frequentes e como estruturar respostas.\nErros comuns de quem busca o primeiro estágio O primeiro erro é se candidatar sem projetos no GitHub. Para estágio em desenvolvimento, um portfólio visível vale mais que cursos pagos sem código público.\nO segundo erro é focar só em frameworks e bibliotecas antes de dominar a linguagem. Quem sabe Kotlin sólido aprende Jetpack Compose, coroutines e Hilt rápido; quem pula a base trava em questões simples de entrevista.\nO terceiro erro é ignorar soft skills. Saber explicar o raciocínio em voz alta, aceitar feedback e perguntar quando não sabe são comportamentos avaliados em toda entrevista — e que pesam tanto quanto o código.\nO quarto erro é desistir após uma ou duas reprovas. Processos seletivos de estágio são concorridos; a aprovação costuma vir após várias tentativas, e cada entrevista é treino para a próxima.\nO quinto erro é não estudar inglês técnico. Boa parte da documentação, dos cursos e das ferramentas está em inglês, e muitas empresas cobram leitura técnica mesmo sem exigir fluência na fala.\nChecklist para conseguir seu estágio em Kotlin e Android Antes de começar a se candidatar, confira:\ndois a quatro projetos de Kotlin/Android publicados no GitHub com README; currículo de uma página com links de contato, GitHub e LinkedIn; fundamentos de Kotlin revisados (null safety, collections, lambdas, funções); pelo menos um app em Jetpack Compose no portfólio; noções de Git (commit, branch, pull request); prática em testes unitários básicos com JUnit; inglês técnico suficiente para ler documentação; candidaturas em pelo menos três fontes (portais, sites de empresas e comunidades). Conclusão Um estágio em Kotlin e Android é uma das portas de entrada mais consistentes para o mercado de tecnologia brasileiro em 2026. A combinação de Android dominante no Brasil, Kotlin como linguagem oficial e um ecossistema maduro de empresas contratantes cria oportunidades reais para quem está disposto a construir um portfólio sólido e se candidatar com método.\nO caminho não é misterioso: estude os fundamentos da linguagem, publique projetos que mostrem código real, prepare-se para entrevistas com antecedência e mantenha constância nas candidaturas. O primeiro \u0026ldquo;sim\u0026rdquo; costuma chegar para quem trata a busca de estágio como um projeto de engenharia — com planejamento, iteração e melhoria contínua a cada entrevista. Para quem quer acelerar ainda mais, completar uma certificação de Kotlin e acompanhar as tendências de Kotlin para 2026 ajudam a conversar de igual para igual com pessoas desenvolvedoras mais experientes já na primeira entrevista.\n","permalink":"https://kotlin.dev.br/blog/estagio-kotlin-android-primeira-vaga-2026/","summary":"\u003cp\u003eConseguir o primeiro estágio em desenvolvimento de software é uma das transições mais importantes da carreira. Em 2026, com Android ainda dominando o mercado brasileiro de mobile e Kotlin consolidada como linguagem oficial recomendada pelo Google, saber Kotlin virou um atalho real para entrar em times de produto de fintechs, marketplaces e empresas de tecnologia. Este guia mostra, de forma prática, como se posicionar, onde procurar e o que esperar de um estágio em Kotlin e Android no Brasil.\u003c/p\u003e","title":"Estágio em Kotlin e Android: Como Conquistar sua Primeira Vaga em 2026 | Kotlin Brasil"},{"content":"Como funciona o processo seletivo de Kotlin no Brasil Conseguir uma vaga de desenvolvedor Kotlin hoje raramente é uma única conversa. O mercado brasileiro — de startups a grandes empresas como iFood e bancos digitais — costuma dividir o processo em quatro a seis etapas. Saber o que esperar em cada uma é metade da preparação.\nUm fluxo típico de processo seletivo para Kotlin, seja na carreira júnior ou na sênior, se parece com isto:\nTriagem de RH ou recrutador — alinhamento de expectativas, pretensão salarial e disponibilidade. Avaliação técnica inicial — quiz, desafio online ou código de baixa complexidade. Entrevista técnica ao vivo — perguntas sobre a linguagem, arquitetura e resolução de problemas. Take-home ou pair programming — projeto prático ou sessão de código com o time. System design ou arquitetura — mais comum para vagas pleno e sênior. Entrevista comportamental e cultural — fit com o time e o negócio. Proposta e negociação — CLT, PJ, benefícios e remoto. Este guia cobre como se preparar para cada uma dessas fases. Para o banco de perguntas técnicas específicas (val vs var, null safety, coroutines, data classes), o artigo de perguntas de entrevista Kotlin é o complemento ideal — aqui o foco é a estratégia de todo o processo.\nO que estudar antes da entrevista A parte técnica de uma vaga Kotlin gira em torno de poucos temas recorrentes. Em vez de tentar revisar tudo, concentre-se no que mais aparece:\nFundamentos da linguagem: null safety, val/var, data class, sealed class, when, funções de escopo (let, run, apply, also, with). Coroutines e Flow: suspend functions, Dispatchers, structured concurrency, StateFlow e SharedFlow. O guia de coroutines aprofunda o tema. Coleções e programação funcional: map, filter, fold, groupBy, sequences e quando usar cada uma. Android (se a vaga for mobile): ciclo de vida, ViewModel, Compose, navegação, persistência com Room. O guia de Jetpack Compose e o roadmap de Android organizam essa trilha. Backend (se a vaga for server-side): Ktor ou Spring, serialização, testes e padrões de API REST. O roadmap de backend Kotlin cobre o caminho completo. Uma tática eficiente é montar uma revisão ativa: escreva pequenos exemplos de cada tema do zero, sem colar de tutoriais. Se você travar em coroutines ou em imutabilidade de coleções, esse é o sinal de onde estudar mais.\nEntrevista técnica ao vivo (live coding) A entrevista ao vivo assusta muita gente, mas ela mede mais comunicação do que velocidade. O entrevistador quer ver como você pensa, como lida com ambiguidade e como comunica decisões.\nEstratégias que funcionam:\nRepita o problema em voz alta para confirmar o entendimento antes de escrever. Pergunte sobre restrições: pode usar a biblioteca padrão? Quais os limites de entrada? Há casos especiais? Pense em voz alta o tempo todo. Silêncio prolongado é interpretado como estar travado. Comece por uma solução simples e correta antes de otimizar. Código que funciona vale mais que otimização prematura. Comente trade-offs enquanto escreve. Mostra maturidade técnica. Exemplo clássico: implementar uma função que valida parenteses balanceados. Primeiro a versão direta, depois conversar sobre complexidade:\nfun parentesesBalanceados(expressao: String): Boolean { var saldo = 0 for (char in expressao) { when (char) { \u0026#39;(\u0026#39; -\u0026gt; saldo++ \u0026#39;)\u0026#39; -\u0026gt; { saldo-- if (saldo \u0026lt; 0) return false } } } return saldo == 0 } Mesmo em uma pergunta simples assim, o entrevistador pode estender: \u0026ldquo;e se houver outros tipos de colchetes?\u0026rdquo; ou \u0026ldquo;como você testaria isso?\u0026rdquo;. Prepare-se para iterar.\nTake-home: entregar valor sem se perder Muitas empresas preferem um projeto take-home em vez de código ao vivo. Ele avalia qualidade de código, organização e critério — mas é fácil exagerar.\nPara entregar um take-home que impressiona:\nSiga o escopo à risca. Não adicione features extras em vez de fazer o básico bem feito. Escreva testes. Mesmo poucos testes de unidade mostram profissionalismo. Documente decisões no README: arquitetura, o que faltou e por quê. Cuide do que é visível: build que funciona, instruções claras, commits organizados. Trate como código de produção, mas sem overengineering. Injeção de dependência e separação de camadas ajudam; quinze abstrações para uma tela única atrapalham. Antes de enviar, confira se o projeto compila do zero seguindo só o README. Peça para um amigo reproduzir o passo a passo se possível.\nSystem design para Android e backend Kotlin System design aparece com frequência em vagas pleno e sênior. No Android, costuma virar \u0026ldquo;como você desenharia o app X\u0026rdquo;; no backend, \u0026ldquo;como escalaria a API Y\u0026rdquo;.\nPara Android, esteja confortável discutindo:\nArquitetura (MVVM, MVI, Clean Architecture) e por que escolher cada uma. Gerenciamento de estado com StateFlow e Compose. Cache, offline-first e sincronização com Room e WorkManager. Modularização e como o time cresce sem se atrapalhar. Performance: inicialização, baseline profiles e traces. Para backend Kotlin, domine:\nModelagem de APIs REST (ou gRPC) e versionamento. Persistência: conexões, transações, migrações e consistência. Concorrência com coroutines e backpressure com Flow. Observabilidade: logs estruturados, métricas e tracing. Resiliência: timeouts, retries, circuit breakers e filas. Em qualquer dos casos, a habilidade central é conversar com o entrevistador, fazer suposições explícitas e justificar escolhas em vez de pular para uma solução.\nEntrevista comportamental: o método STAR A entrevista comportamental avalia como você lida com conflito, prioridades, fracassos e colaboração. O método STAR mantém suas respostas objetivas:\nSituação — contexto relevante do problema. Tarefa — qual era sua responsabilidade. Ação — o que você fez, com foco no seu papel. Resultado — desfecho mensurável e o que aprendeu. Perguntas recorrentes para devs Kotlin:\n\u0026ldquo;Conte sobre um bug difícil que você resolveu.\u0026rdquo; \u0026ldquo;Descreva uma discordância técnica com um colega.\u0026rdquo; \u0026ldquo;Fale de uma entrega com prazo apertado e como você priorizou.\u0026rdquo; \u0026ldquo;Quando você escolheu Kotlin/uma biblioteca e se arrependeu?\u0026rdquo; \u0026ldquo;Como você lida com revisão de código e feedback?\u0026rdquo; Prepare três ou quatro histórias reais que se adaptem a várias perguntas. Resultados com números (tempo de build reduzido, crash rate baixado, retrabalho evitado) dão peso à resposta.\nPerguntas para fazer ao entrevistador Fazer boas perguntas demonstra interesse e ajuda você a avaliar a empresa de volta. Algumas úteis:\nComo é o fluxo de um Pull Request típico no time? Qual a maior dor técnica atual do produto? Como o time decide entre dívida técnica e novas features? Como é o processo de code review e onboarding? Qual a participação de Kotlin/Android (ou backend) na arquitetura geral? As respostas revelam muito sobre maturidade técnica, cultura e se o ambiente combina com você.\nNegociação de proposta: CLT, PJ e remoto Receber a proposta não é o fim do processo — é onde muita gente deixa dinheiro na mesa. Antes de negociar, entenda os regimes comuns no Brasil:\nCLT oferece estabilidade, 13º, férias, FGTS e benefícios, mas com menor líquido mensal. PJ costuma ter bruto maior, mas você paga contador, impostos e cobre benefícios. Remoto pode ser CLT ou PJ e muda o custo de vida — compare sempre o líquido real. Tenha uma faixa de referência. As páginas de salário júnior, pleno e sênior trazem faixas atualizadas para Kotlin no Brasil. Negocie o pacote completo (salário, bônus, VR/VA, plano de saúde, equipamento, verba de estudo), não só o número base.\nSe houver vagas remotas concorrendo, use isso como elemento de negociação. E nunca aceite uma proposta verbalmente no mesmo dia sem revisar o contrato por escrito.\nErros comuns que custam vagas Decorar respostas em vez de entender conceitos. Entrevistadores percebem e aprofundam. Silenciar durante a live coding. Pensar em voz alta é parte da avaliação. Ignorar testes no take-home e na entrevista ao vivo. Falar mal de empregadores anteriores na comportamental. Não ter portfólio visível. Um portfólio de desenvolvedor Kotlin bem montado abre portas antes da entrevista. Aceitar a primeira proposta sem negociar ou comparar. Checklist de preparação Antes de uma entrevista de Kotlin/Android/backend, garanta que você:\nRevisou os fundamentos da linguagem e coroutines; Treinou ao menos três live codings em voz alta; Montou um take-home de referência bem documentado; Preparou histórias STAR para comportamental; Listou perguntas para o entrevistador; Pesquisou a faixa salarial para a senioridade alvo; Revisou o portfólio e o LinkedIn; Testou câmera, microfone e ambiente para entrevistas remotas. Perguntas frequentes Preciso saber Android e backend para passar em vagas de Kotlin? Não. A maioria das vagas é especializada em mobile ou server-side. Conhecer o outro lado ajuda em perguntas de arquitetura, mas o foco da entrevista acompanha a vaga. Veja a diferença nos roadmaps de Android e backend.\nQuanto tempo de preparação é suficiente? Para quem já programa em Kotlin, duas a quatro semanas de prática dirigida costumam bastar. Quem está migrando de Java pode precisar de mais tempo — o guia de transição de Java para Kotlin ajuda a estimar.\nTake-home vale a pena quando é não remunerado? Depende do seu momento. Projetos longos e não pagos podem ser exploratórios; desafios curtos e bem definidos costumam ser justos. Avalie o custo de oportunidade e o tamanho real do pedido.\nComo me saio bem se travar em uma pergunta técnica? Admita com honestidade, relate o que você sabe e proponha como investigaria. Dizer \u0026ldquo;não sei, mas pesquisaria assim\u0026rdquo; vale muito mais que inventar. Entrevistadores respeitam transparência.\nConclusão Preparar-se para uma entrevista de desenvolvedor Kotlin é um processo de etapas, não de respostas decoradas. Conheça o fluxo do processo seletivo, revisite os fundamentos da linguagem, treine live coding em voz alta, capriche no take-home, ensaie histórias comportamentais e chegue à negociação com dados de mercado.\nO candidato que se destaca raramente é o que sabe tudo de cor: é o que comunica raciocínio claro, demonstra maturidade técnica e entende o negócio. Com a preparação certa — e o conjunto de perguntas de entrevista, roadmaps e faixas de salário deste portal — você chega confiante a qualquer processo seletivo de Kotlin em 2026.\n","permalink":"https://kotlin.dev.br/carreira/como-preparar-entrevista-kotlin-android/","summary":"\u003ch2 id=\"como-funciona-o-processo-seletivo-de-kotlin-no-brasil\"\u003eComo funciona o processo seletivo de Kotlin no Brasil\u003c/h2\u003e\n\u003cp\u003eConseguir uma vaga de \u003cstrong\u003edesenvolvedor Kotlin\u003c/strong\u003e hoje raramente é uma única conversa. O mercado brasileiro — de startups a grandes empresas como \u003ca href=\"/empresas/ifood/\"\u003eiFood\u003c/a\u003e e bancos digitais — costuma dividir o processo em quatro a seis etapas. Saber o que esperar em cada uma é metade da preparação.\u003c/p\u003e\n\u003cp\u003eUm fluxo típico de processo seletivo para Kotlin, seja na \u003ca href=\"/carreira/salario-dev-kotlin-junior/\"\u003ecarreira júnior\u003c/a\u003e ou na \u003ca href=\"/carreira/salario-dev-kotlin-senior/\"\u003esênior\u003c/a\u003e, se parece com isto:\u003c/p\u003e","title":"Como se Preparar para Entrevista de Kotlin e Android: Guia 2026 | Kotlin Brasil"},{"content":"Se você já construiu uma tela com Jetpack Compose, em algum momento precisa responder a uma pergunta inevitável: como o usuário sai daqui e vai para lá? A resposta canônica, estável e amplamente adotada em produção é o Navigation Compose — o componente do AndroidX que traz NavHost, NavController e grafos de navegação declarativos para o mundo das funções composáveis.\nNeste guia completo, você vai dominar o Navigation Compose do zero ao avançado: configuração, NavHost, NavController, rotas type-safe, argumentos, bottom navigation, grafos aninhados, deep links, salvamento de estado e boas práticas de arquitetura. Se você está começando, leia antes o tutorial de Compose para iniciantes e o conteúdo sobre Kotlin para Android para fixar a base.\nO que é o Navigation Compose? O Navigation Compose é a integração oficial da biblioteca AndroidX Navigation com o Jetpack Compose. Enquanto a navegação clássica nasceu no mundo de Activities e Fragments (NavigationUI, NavHostFragment, gráficos em XML), esta versão substitui o XML por composables e expõe o NavController como algo que você segura no nível do seu app.\nOs pilares são três:\nNavController — o objeto central que conhece a back stack, o destino atual e expõe navigate() e popBackStack(). NavHost — um composable que desenha o destino correspondente ao estado atual do NavController. É nele que você registra todas as telas. Destination / Route — a definição de cada tela, que pode receber argumentos tipados e ser protegida por lógica. A grande vantagem sobre soluções caseiras (listas de estado com when) é que o Navigation Compose resolve, de forma testada, os problemas difíceis que aparecem em todo app real: back stack, state saving, deep links, transições, resultado entre telas e integração com o botão de voltar do sistema.\nDependências e configuração No seu build.gradle.kts (módulo :app), adicione o artefato navigation-compose:\ndependencies { val navVersion = \u0026#34;2.8.5\u0026#34; implementation(\u0026#34;androidx.navigation:navigation-compose:$navVersion\u0026#34;) } Se você gerencia versões em catálogo — o que recomendamos, veja o guia de Version Catalog — basta registrar a lib no libs.versions.toml:\n[versions] navigationCompose = \u0026#34;2.8.5\u0026#34; [libraries] androidx-navigation-compose = { group = \u0026#34;androidx.navigation\u0026#34;, name = \u0026#34;navigation-compose\u0026#34;, version.ref = \u0026#34;navigationCompose\u0026#34; } implementation(libs.androidx.navigation.compose) NavController: o coração da navegação A regra de ouro do Navigation Compose é uma única instância de NavController por app, geralmente retida no nível mais alto da sua UI. Em Compose, você a cria com rememberNavController():\n@Composable fun KotlinBrasilApp() { val navController = rememberNavController() KotlinBrasilTheme { Scaffold { innerPadding -\u0026gt; KotlinNavHost( navController = navController, modifier = Modifier.padding(innerPadding), ) } } } Por que segurar o NavController lá em cima? Porque a barra inferior, a top bar e o NavHost precisam enxergar o mesmo controlador para reagir ao destino atual (por exemplo, esconder a bottom bar na tela de login). Em apps que usam injeção de dependência, o guia de Hilt com Compose mostra como fornecer ViewModels que conversam com a navegação sem acoplar UI a regras de negócio.\nNavHost: registrando destinos O NavHost recebe o NavController, o destino inicial e um bloco composable { } para cada tela:\n@Composable fun KotlinNavHost( navController: NavController, modifier: Modifier = Modifier, ) { NavHost( navController = navController, startDestination = \u0026#34;home\u0026#34;, modifier = modifier, ) { composable(\u0026#34;home\u0026#34;) { HomeScreen( onOpenArticle = { id -\u0026gt; navController.navigate(\u0026#34;article/$id\u0026#34;) }, ) } composable( route = \u0026#34;article/{articleId}\u0026#34;, arguments = listOf(navArgument(\u0026#34;articleId\u0026#34;) { type = NavType.StringType }), ) { backStackEntry -\u0026gt; val articleId = backStackEntry.arguments?.getString(\u0026#34;articleId\u0026#34;).orEmpty() ArticleScreen(articleId = articleId) } } } Aqui já aparecem três conceitos chave: a rota (\u0026quot;home\u0026quot;, \u0026quot;article/{articleId}\u0026quot;), o placeholder de argumento ({articleId}) e o navArgument que define o tipo esperado. O backStackEntry entregue ao composable de destino carrega os argumentos já parseados.\nRotas type-safe com objetos serializáveis A partir do AndroidX Navigation 2.8.0, você pode abandonar as strings mágicas e usar rotas serializáveis, que dão segurança de tipos em tempo de compilação. Defina cada destino como um object ou data class marcado com @Serializable (conceito explicado em detalhe no nosso glossário de Serialization e no artigo de serialização avançada e polimorfismo):\nimport kotlinx.serialization.Serializable @Serializable object Home @Serializable data class Article(val articleId: String) @Serializable data class Search(val query: String = \u0026#34;\u0026#34;) @Composable fun KotlinNavHost(navController: NavController) { NavHost(navController, startDestination = Home) { composable\u0026lt;Home\u0026gt; { HomeScreen(onOpenArticle = { id -\u0026gt; navController.navigate(Article(id)) }) } composable\u0026lt;Article\u0026gt; { backStackEntry -\u0026gt; val article: Article = backStackEntry.toRoute() ArticleScreen(articleId = article.articleId) } composable\u0026lt;Search\u0026gt; { backStackEntry -\u0026gt; val search: Search = backStackEntry.toRoute() SearchScreen(initialQuery = search.query) } } } As vantagens são diretas: o compilador reclama se você passar o tipo errado, não há concatenação de string para montar URLs e os argumentos opcionais viram parâmetros com valor padrão. Sempre que possível, prefira esta abordagem em vez de rotas como string.\nArgumentos opcionais e valores padrão Argumentos opcionais precisam de defaultValue e de nullable = true. Com rotas type-safe, isso desaparece — basta usar val query: String = \u0026quot;\u0026quot;. Se você ainda está em strings, o equivalente é:\ncomposable( route = \u0026#34;search?q={query}\u0026#34;, arguments = listOf(navArgument(\u0026#34;query\u0026#34;) { type = NavType.StringType defaultValue = \u0026#34;\u0026#34; nullable = true }), ) Bottom navigation integrada Um padrão clássico é casar NavigationBar (Material 3) com o NavHost. O truque é manter a back stack do destino raiz de cada aba para preservar estado ao trocar de tab:\n@Composable fun MainScreen(navController: NavController) { val items = listOf(Tab.Home, Tab.Search, Tab.Profile) Scaffold( bottomBar = { val currentBackStack by navController.currentBackStackEntryAsState() val currentDestination = currentBackStack?.destination NavigationBar { items.forEach { tab -\u0026gt; NavigationBarItem( selected = currentDestination?.hierarchy?.any { it.route == tab.route } == true, onClick = { navController.navigate(tab.route) { popUpTo(navController.graph.findStartDestination().id) { saveState = true } launchSingleTop = true restoreState = true } }, icon = { Icon(tab.icon, contentDescription = tab.label) }, label = { Text(tab.label) }, ) } } }, ) { innerPadding -\u0026gt; KotlinNavHost(navController, Modifier.padding(innerPadding)) } } Os detalhes que fazem a diferença são: popUpTo com saveState = true, launchSingleTop = true e restoreState = true. Sem eles, toda vez que o usuário volta a uma aba você recria a tela do zero e perde a posição de rolagem. O design da barra segue as recomendações de Material 3 Expressive com Compose e os layouts de Compose.\nGrafos aninhados Para fluxos fechados (checkout, onboarding, wizard), use navigation { } dentro do NavHost para criar um subgrafo com sua própria rota de entrada:\nnavigation(startDestination = Checkout.Cart, route = \u0026#34;checkout\u0026#34;) { composable\u0026lt;Checkout.Cart\u0026gt; { CartScreen(onNext = { navController.navigate(Checkout.Address) }) } composable\u0026lt;Checkout.Address\u0026gt; { AddressScreen(onNext = { navController.navigate(Checkout.Payment) }) } composable\u0026lt;Checkout.Payment\u0026gt; { PaymentScreen(onDone = { navController.popBackStack() }) } } Assim você navega para \u0026quot;checkout\u0026quot; e o usuário fica preso ao fluxo até terminar — o botão de voltar do sistema respeita a back stack interna.\nDeep links e App Links O NavHost aceita deepLinks por destino, conectando rotas internas a URLs reais (o que casca bem com o guia de App Links e deep links com Kotlin):\ncomposable\u0026lt;Article\u0026gt;( deepLinks = listOf(navDeepLink { uriPattern = \u0026#34;https://kotlin.dev.br/artigos/{articleId}\u0026#34; }), ) { entry -\u0026gt; val article: Article = entry.toRoute() ArticleScreen(article.articleId) } Depois registre o intent-filter correspondente no AndroidManifest.xml para que links externos (notificações, e-mails, busca) abram direto na tela certa.\nResultado entre telas Para devolver um valor (selecionar um item, criar algo), use savedStateHandle:\n// Tela que pede um resultado val result = navController.currentBackStackEntry ?.savedStateHandle ?.getStateFlow\u0026lt;String\u0026gt;(\u0026#34;selectedCategory\u0026#34;, \u0026#34;\u0026#34;) ?.collectAsState() navController.navigate(\u0026#34;categoryPicker\u0026#34;) // Tela que devolve o resultado navController.previousBackStackEntry?.savedStateHandle?.set(\u0026#34;selectedCategory\u0026#34;, \u0026#34;coroutines\u0026#34;) navController.popBackStack() Como o savedStateHandle sobrevive a mudanças de configuração, o resultado chega de forma confiável. Para testar esses fluxos reativos, o guia de testes com Turbine e StateFlow é leitura obrigatória.\nEstado, back stack e boas práticas Algumas regras que evitam bugs difíceis em produção:\nNunca passe o NavController para dentro de ViewModels ou repositórios. A navegação é uma preocupação de UI. Centralize as rotas em um único lugar (objetos @Serializable ou constantes) para evitar strings duplicadas. Use popUpTo com cuidado: esquecer o saveState é a causa nº 1 de telas que \u0026ldquo;resetam\u0026rdquo; ao trocar de aba. Para telas que devem sobreviver a morte do processo, confie no savedStateHandle e persista dados críticos em DataStore, não em remember. Modele estados de UI com sealed classes para que cada destino saiba exatamente quais eventos de navegação pode emitir. Quando considerar Navigation 3 O Navigation Compose descrito aqui é a solução estável e é o que a maioria dos apps em produção usa hoje. Existe uma versão mais nova, o Navigation 3, que trata a navegação como estado puro com back stack tipada e integração ainda mais idiomática com Compose. Vale acompanhar — já cobrimos o guia do Navigation 3 com Compose — mas, para novos projetos em 2026 que precisam de estabilidade e material de referência maduro, o Navigation Compose clássico continua sendo a escolha segura.\nConclusão O Navigation Compose é a fundação de navegação do Android moderno. Dominar NavController, NavHost, rotas type-safe, bottom navigation, grafos aninhados, deep links e savedStateHandle te coloca em posição de arquitetar qualquer fluxo — do app mais simples ao e-commerce com checkout multistep. Comece com rotas serializáveis desde o primeiro dia, mantenha o NavController isolado na UI e deixe que padrões como saveState/restoreState façam o trabalho pesado de preservar a experiência do usuário.\nSe quiser ir além, conecte navegação a boas práticas de injeção de dependência com Hilt, layouts de Compose e persistência com DataStore para construir apps Android robustos e mantíveis com Kotlin.\n","permalink":"https://kotlin.dev.br/blog/navigation-compose-navhost-navcontroller-kotlin-2026/","summary":"\u003cp\u003eSe você já construiu uma tela com \u003ca href=\"/guias/guia-jetpack-compose/\"\u003eJetpack Compose\u003c/a\u003e, em algum momento precisa responder a uma pergunta inevitável: \u003cstrong\u003ecomo o usuário sai daqui e vai para lá?\u003c/strong\u003e A resposta canônica, estável e amplamente adotada em produção é o \u003cstrong\u003eNavigation Compose\u003c/strong\u003e — o componente do AndroidX que traz \u003ccode\u003eNavHost\u003c/code\u003e, \u003ccode\u003eNavController\u003c/code\u003e e grafos de navegação declarativos para o mundo das funções composáveis.\u003c/p\u003e\n\u003cp\u003eNeste guia completo, você vai dominar o Navigation Compose do zero ao avançado: configuração, \u003ccode\u003eNavHost\u003c/code\u003e, \u003ccode\u003eNavController\u003c/code\u003e, rotas type-safe, argumentos, bottom navigation, grafos aninhados, deep links, salvamento de estado e boas práticas de arquitetura. Se você está começando, leia antes o \u003ca href=\"/tutoriais/jetpack-compose-basico/\"\u003etutorial de Compose para iniciantes\u003c/a\u003e e o conteúdo sobre \u003ca href=\"/blog/kotlin-para-android/\"\u003eKotlin para Android\u003c/a\u003e para fixar a base.\u003c/p\u003e","title":"Navigation Compose: Guia Completo do NavHost e NavController | Kotlin Brasil"},{"content":"Sobre a vagaA Campspot busca uma pessoa Analista de Dados e Negócios em regime de contrato, nível júnior, para atuação presencial no Brasil.\nRequisitos e tecnologiasConhecimento em SQL para consultas e análise de dados.Familiaridade com linguagens como Kotlin, Java, JavaScript ou Python.Experiência ou noções de bancos e plataformas de dados como MySQL e Snowflake.Conhecimento em ferramentas de dados como dbt e Apache Airflow.Uso de Git para versionamento.FormatoContrato.Nível júnior.Atuação presencial no Brasil. ","permalink":"https://kotlin.dev.br/vagas/exp360mxpeeml8xi-campspot-analista-de-dados-e-negocios-contrato/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Campspot busca uma pessoa Analista de Dados e Negócios em regime de contrato, nível júnior, para atuação presencial no Brasil.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eSQL\u003c/strong\u003e para consultas e análise de dados.\u003c/li\u003e\u003cli\u003eFamiliaridade com linguagens como \u003cstrong\u003eKotlin\u003c/strong\u003e, \u003cstrong\u003eJava\u003c/strong\u003e, \u003cstrong\u003eJavaScript\u003c/strong\u003e ou \u003cstrong\u003ePython\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência ou noções de bancos e plataformas de dados como \u003cstrong\u003eMySQL\u003c/strong\u003e e \u003cstrong\u003eSnowflake\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em ferramentas de dados como \u003cstrong\u003edbt\u003c/strong\u003e e \u003cstrong\u003eApache Airflow\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eGit\u003c/strong\u003e para versionamento.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFormato\u003c/h3\u003e\u003cul\u003e\u003cli\u003eContrato.\u003c/li\u003e\u003cli\u003eNível júnior.\u003c/li\u003e\u003cli\u003eAtuação presencial no Brasil.\u003c/li\u003e\u003c/ul\u003e","title":"Analista de Dados e Negócios (Contrato)"},{"content":"Sobre a vagaA CI\u0026T busca uma pessoa Desenvolvedora Android Sênior para atuar presencialmente em Campinas, São Paulo, em projetos mobile Android.\nStack e contexto técnicoDesenvolvimento Android com Kotlin e Java.Arquiteturas e padrões como MVVM, MVC e Clean Architecture.Injeção de dependência com Dagger e Hilt.Integrações via REST.Testes com JUnit, Espresso e Appium.Versionamento e CI/CD com Git, Git Flow e GitHub Actions.Uso de Material Design e ferramentas como Adobe Target, Adobe Analytics e AEM.RequisitosExperiência sênior em desenvolvimento Android.Conhecimento sólido em Kotlin, Java e boas práticas de arquitetura mobile.Experiência com testes automatizados, integração contínua e colaboração com times de engenharia.Disponibilidade para trabalho presencial em Campinas, São Paulo. ","permalink":"https://kotlin.dev.br/vagas/ua9d1at8426pfbin-ci-t-desenvolvedor-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T busca uma pessoa Desenvolvedora Android Sênior para atuar presencialmente em Campinas, São Paulo, em projetos mobile Android.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolvimento Android com \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eJava\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eArquiteturas e padrões como \u003cstrong\u003eMVVM\u003c/strong\u003e, \u003cstrong\u003eMVC\u003c/strong\u003e e \u003cstrong\u003eClean Architecture\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eInjeção de dependência com \u003cstrong\u003eDagger\u003c/strong\u003e e \u003cstrong\u003eHilt\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eIntegrações via \u003cstrong\u003eREST\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eTestes com \u003cstrong\u003eJUnit\u003c/strong\u003e, \u003cstrong\u003eEspresso\u003c/strong\u003e e \u003cstrong\u003eAppium\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVersionamento e CI/CD com \u003cstrong\u003eGit\u003c/strong\u003e, \u003cstrong\u003eGit Flow\u003c/strong\u003e e \u003cstrong\u003eGitHub Actions\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eMaterial Design\u003c/strong\u003e e ferramentas como \u003cstrong\u003eAdobe Target\u003c/strong\u003e, \u003cstrong\u003eAdobe Analytics\u003c/strong\u003e e \u003cstrong\u003eAEM\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin, Java e boas práticas de arquitetura mobile.\u003c/li\u003e\u003cli\u003eExperiência com testes automatizados, integração contínua e colaboração com times de engenharia.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho presencial em Campinas, São Paulo.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android Sênior"},{"content":"Sobre a vagaA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior - Android para atuação remota, com base em Quito ou Lima.\nRequisitos e tecnologiasExperiência sênior em desenvolvimento Android.Conhecimento em Kotlin e Jetpack Compose.Experiência com Gradle no ecossistema Android.Familiaridade com automação e entrega mobile usando Fastlane.Modelo de trabalhoVaga remota para profissionais localizados em Quito ou Lima.\n","permalink":"https://kotlin.dev.br/vagas/6jguve9y95x1kmby-thoughtworks-desenvolvedor-mobile-senior-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior - Android para atuação remota, com base em Quito ou Lima.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eJetpack Compose\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eGradle\u003c/strong\u003e no ecossistema Android.\u003c/li\u003e\u003cli\u003eFamiliaridade com automação e entrega mobile usando \u003cstrong\u003eFastlane\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais localizados em Quito ou Lima.\u003c/p\u003e","title":"Desenvolvedor Mobile Sênior - Android"},{"content":"Sobre a vagaA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior com foco em Android para atuação remota a partir de Quito, Lima ou Peru.\nRequisitosExperiência sênior em desenvolvimento mobile Android.Conhecimento em Kotlin e Jetpack Compose.Experiência com Gradle.Familiaridade com fastlane para automação de builds e entregas mobile.Informações da vagaEmpresa: Thoughtworks.Senioridade: Sênior.Modelo de trabalho: remoto.Localização: Quito, Lima ou Peru. ","permalink":"https://kotlin.dev.br/vagas/0kytov5su889320r-thoughtworks-desenvolvedor-a-mobile-senior-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior com foco em Android para atuação remota a partir de Quito, Lima ou Peru.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento mobile Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin e Jetpack Compose.\u003c/li\u003e\u003cli\u003eExperiência com Gradle.\u003c/li\u003e\u003cli\u003eFamiliaridade com fastlane para automação de builds e entregas mobile.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eInformações da vaga\u003c/h3\u003e\u003cul\u003e\u003cli\u003eEmpresa: Thoughtworks.\u003c/li\u003e\u003cli\u003eSenioridade: Sênior.\u003c/li\u003e\u003cli\u003eModelo de trabalho: remoto.\u003c/li\u003e\u003cli\u003eLocalização: Quito, Lima ou Peru.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Mobile Sênior - Android"},{"content":"Sobre a vagaA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior para atuar remotamente em projetos com React Native e ecossistema mobile.\nRequisitosExperiência sênior em desenvolvimento mobile.Vivência com React Native, JavaScript e TypeScript.Conhecimento em desenvolvimento nativo com Swift e Kotlin.Experiência com testes usando Jest e React Native Testing Library.Familiaridade com automação e build mobile usando fastlane, EAS e Gradle.Local de trabalhoVaga remota para Quito ou Equador.\n","permalink":"https://kotlin.dev.br/vagas/0h3bkkp29zdkb460-thoughtworks-desenvolvedor-a-mobile-senior-react-native/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior para atuar remotamente em projetos com React Native e ecossistema mobile.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento mobile.\u003c/li\u003e\u003cli\u003eVivência com \u003cstrong\u003eReact Native\u003c/strong\u003e, \u003cstrong\u003eJavaScript\u003c/strong\u003e e \u003cstrong\u003eTypeScript\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em desenvolvimento nativo com \u003cstrong\u003eSwift\u003c/strong\u003e e \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com testes usando \u003cstrong\u003eJest\u003c/strong\u003e e \u003cstrong\u003eReact Native Testing Library\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eFamiliaridade com automação e build mobile usando \u003cstrong\u003efastlane\u003c/strong\u003e, \u003cstrong\u003eEAS\u003c/strong\u003e e \u003cstrong\u003eGradle\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para Quito ou Equador.\u003c/p\u003e","title":"Desenvolvedor(a) Mobile Sênior - React Native"},{"content":"Sobre a vagaA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior com foco em React Native para atuação remota, com base em Lima, Quito ou Equador.\nStack e práticasReact Native, JavaScript e TypeScript.Swift, Kotlin e Gradle no ecossistema mobile.Testes com Jest e React Native Testing Library.Automação e entrega mobile com fastlane e EAS.Práticas ágeis como Extreme Programming (XP), Scrum e Kanban.PerfilExperiência sênior em desenvolvimento mobile.Vivência com aplicações React Native em produção.Capacidade de trabalhar de forma remota em times colaborativos. ","permalink":"https://kotlin.dev.br/vagas/abfpihm2dj7hir4c-thoughtworks-desenvolvedor-a-mobile-senior-react-native/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior com foco em React Native para atuação remota, com base em Lima, Quito ou Equador.\u003c/p\u003e\u003ch3\u003eStack e práticas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eReact Native, JavaScript e TypeScript.\u003c/li\u003e\u003cli\u003eSwift, Kotlin e Gradle no ecossistema mobile.\u003c/li\u003e\u003cli\u003eTestes com Jest e React Native Testing Library.\u003c/li\u003e\u003cli\u003eAutomação e entrega mobile com fastlane e EAS.\u003c/li\u003e\u003cli\u003ePráticas ágeis como Extreme Programming (XP), Scrum e Kanban.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento mobile.\u003c/li\u003e\u003cli\u003eVivência com aplicações React Native em produção.\u003c/li\u003e\u003cli\u003eCapacidade de trabalhar de forma remota em times colaborativos.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Mobile Sênior - React Native"},{"content":"Sobre a vagaA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior para atuar remotamente em projetos com foco em React Native.\nRequisitos e tecnologiasExperiência sênior em desenvolvimento mobile.React Native, JavaScript e TypeScript.Conhecimento em Swift e Kotlin.Testes com Jest e React Native Testing Library.Ferramentas de build e entrega como fastlane, EAS e Gradle.Local de trabalhoVaga remota vinculada a Quito, Pichincha, Equador.\n","permalink":"https://kotlin.dev.br/vagas/o17ar7z35r11z5x4-thoughtworks-desenvolvedor-a-mobile-senior-react-native/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior para atuar remotamente em projetos com foco em React Native.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento mobile.\u003c/li\u003e\u003cli\u003eReact Native, JavaScript e TypeScript.\u003c/li\u003e\u003cli\u003eConhecimento em Swift e Kotlin.\u003c/li\u003e\u003cli\u003eTestes com Jest e React Native Testing Library.\u003c/li\u003e\u003cli\u003eFerramentas de build e entrega como fastlane, EAS e Gradle.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota vinculada a Quito, Pichincha, Equador.\u003c/p\u003e","title":"Desenvolvedor(a) Mobile Sênior - React Native"},{"content":"Sobre a vagaA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior para atuar remotamente em projetos com React Native e tecnologias mobile.\nRequisitosExperiência sênior em desenvolvimento mobile com React Native.Conhecimento em JavaScript e TypeScript.Experiência ou familiaridade com desenvolvimento nativo usando Swift e Kotlin.Experiência com testes usando Jest e React Native Testing Library.Vivência com práticas ágeis como Extreme Programming (XP), Scrum ou Kanban.Tecnologias e ferramentasReact Native, JavaScript, TypeScript, Swift e Kotlin.Jest e React Native Testing Library.fastlane, EAS e Gradle.Local de trabalhoVaga remota para pessoas em Lima ou Quito.\n","permalink":"https://kotlin.dev.br/vagas/xiqngqgwxlqq1wj8-thoughtworks-desenvolvedor-a-mobile-senior-react-native/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior para atuar remotamente em projetos com React Native e tecnologias mobile.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento mobile com \u003cstrong\u003eReact Native\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eJavaScript\u003c/strong\u003e e \u003cstrong\u003eTypeScript\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência ou familiaridade com desenvolvimento nativo usando \u003cstrong\u003eSwift\u003c/strong\u003e e \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com testes usando \u003cstrong\u003eJest\u003c/strong\u003e e \u003cstrong\u003eReact Native Testing Library\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com práticas ágeis como \u003cstrong\u003eExtreme Programming (XP)\u003c/strong\u003e, \u003cstrong\u003eScrum\u003c/strong\u003e ou \u003cstrong\u003eKanban\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias e ferramentas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eReact Native, JavaScript, TypeScript, Swift e Kotlin.\u003c/li\u003e\u003cli\u003eJest e React Native Testing Library.\u003c/li\u003e\u003cli\u003efastlane, EAS e Gradle.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para pessoas em Lima ou Quito.\u003c/p\u003e","title":"Desenvolvedor(a) Mobile Sênior - React Native"},{"content":"Sobre a vagaA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior Android para atuação remota a partir de Lima, Peru.\nStack principalKotlinAndroidJetpack ComposeGradlefastlanePerfilSenioridade: SêniorExperiência em desenvolvimento mobile AndroidAtuação com ferramentas de build e automação para apps Android ","permalink":"https://kotlin.dev.br/vagas/ey4kswrzdwdks22z-thoughtworks-desenvolvedor-a-mobile-senior-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Thoughtworks busca uma pessoa Desenvolvedora Mobile Sênior Android para atuação remota a partir de Lima, Peru.\u003c/p\u003e\u003ch3\u003eStack principal\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eAndroid\u003c/li\u003e\u003cli\u003eJetpack Compose\u003c/li\u003e\u003cli\u003eGradle\u003c/li\u003e\u003cli\u003efastlane\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cul\u003e\u003cli\u003eSenioridade: Sênior\u003c/li\u003e\u003cli\u003eExperiência em desenvolvimento mobile Android\u003c/li\u003e\u003cli\u003eAtuação com ferramentas de build e automação para apps Android\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Mobile Sênior Android"},{"content":"Sobre a vagaO C6 Bank busca uma Pessoa Desenvolvedora Backend Sênior para atuar presencialmente em São Paulo na área de CRM Engineering.\nResponsabilidadesDesenvolver e manter serviços backend usando Kotlin e Java.Trabalhar com integrações e soluções para CRM.Atuar com mensageria, bancos de dados e serviços em nuvem.RequisitosExperiência sênior em desenvolvimento backend.Conhecimento em Kotlin, Java e Spring Boot.Experiência com PostgreSQL, MongoDB, Kafka, SQS e SNS.Vivência com AWS ou GCP.Conhecimento em Salesforce, Marketing Cloud ou URA é relevante para o contexto da área.Modelo de trabalhoVaga presencial em São Paulo, São Paulo.\n","permalink":"https://kotlin.dev.br/vagas/m9zh99p2o8og9et8-c6-bank-pessoa-desenvolvedora-backend-senior-kotlin-java-crm-en/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma Pessoa Desenvolvedora Backend Sênior para atuar presencialmente em São Paulo na área de CRM Engineering.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend usando Kotlin e Java.\u003c/li\u003e\u003cli\u003eTrabalhar com integrações e soluções para CRM.\u003c/li\u003e\u003cli\u003eAtuar com mensageria, bancos de dados e serviços em nuvem.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento backend.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Java e Spring Boot.\u003c/li\u003e\u003cli\u003eExperiência com PostgreSQL, MongoDB, Kafka, SQS e SNS.\u003c/li\u003e\u003cli\u003eVivência com AWS ou GCP.\u003c/li\u003e\u003cli\u003eConhecimento em Salesforce, Marketing Cloud ou URA é relevante para o contexto da área.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em São Paulo, São Paulo.\u003c/p\u003e","title":"Pessoa Desenvolvedora Backend Sênior Kotlin/Java | CRM Engineering"},{"content":"Sobre a vagaVaga sênior presencial no C6 Bank, em São Paulo, para atuação em Investments Engineering como pessoa desenvolvedora especialista Back-end com Java e Kotlin.\nStack e práticasKotlin, Java e Spring Boot.PostgreSQL e MongoDB.Kafka, SQS e SNS.AWS, Terraform e CloudFormation.CI/CD, TDD, BDD e DDD.JWT e OAuth2.RequisitosExperiência sênior em desenvolvimento Back-end.Vivência com sistemas distribuídos, mensageria e integrações em nuvem.Conhecimento em bancos relacionais e NoSQL.Prática com testes, entrega contínua e desenho orientado a domínio. ","permalink":"https://kotlin.dev.br/vagas/5l5ikhqfcm7p62nh-c6-bank-pessoa-desenvolvedora-especialista-back-end-java-e-kotl/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga sênior presencial no C6 Bank, em São Paulo, para atuação em Investments Engineering como pessoa desenvolvedora especialista Back-end com Java e Kotlin.\u003c/p\u003e\u003ch3\u003eStack e práticas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java e Spring Boot.\u003c/li\u003e\u003cli\u003ePostgreSQL e MongoDB.\u003c/li\u003e\u003cli\u003eKafka, SQS e SNS.\u003c/li\u003e\u003cli\u003eAWS, Terraform e CloudFormation.\u003c/li\u003e\u003cli\u003eCI/CD, TDD, BDD e DDD.\u003c/li\u003e\u003cli\u003eJWT e OAuth2.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Back-end.\u003c/li\u003e\u003cli\u003eVivência com sistemas distribuídos, mensageria e integrações em nuvem.\u003c/li\u003e\u003cli\u003eConhecimento em bancos relacionais e NoSQL.\u003c/li\u003e\u003cli\u003ePrática com testes, entrega contínua e desenho orientado a domínio.\u003c/li\u003e\u003c/ul\u003e","title":"Pessoa Desenvolvedora Especialista Back-end Java e Kotlin"},{"content":"Sobre a vagaA Inter\u0026amp;Co busca uma pessoa Analista Desenvolvedora de Software III Android, com foco em Kotlin, para atuação presencial em Belo Horizonte, Minas Gerais.\nRequisitos e tecnologiasExperiência sênior em desenvolvimento Android.Conhecimento em Kotlin.Experiência ou familiaridade com Jetpack Compose, MVVM, Gradle, Fastlane e publicação na Play Store.Conhecimento em tecnologias mobile como React Native ou Flutter pode ser relevante para o contexto da vaga.Local de trabalhoVaga presencial em Belo Horizonte, Minas Gerais, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/404g646fnqoj723g-inter-co-analista-desenvolvedor-de-software-iii-android-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Inter\u0026amp;Co busca uma pessoa Analista Desenvolvedora de Software III Android, com foco em Kotlin, para atuação presencial em Belo Horizonte, Minas Gerais.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência ou familiaridade com Jetpack Compose, MVVM, Gradle, Fastlane e publicação na Play Store.\u003c/li\u003e\u003cli\u003eConhecimento em tecnologias mobile como React Native ou Flutter pode ser relevante para o contexto da vaga.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em Belo Horizonte, Minas Gerais, Brasil.\u003c/p\u003e","title":"Analista Desenvolvedor de Software III Android (Kotlin)"},{"content":"Sobre a vagaA Devexperts busca uma pessoa Desenvolvedora Java Pleno/Sênior para atuar em projetos backend, com modelo híbrido e base em São Paulo ou Brasil.\nResponsabilidadesDesenvolver e manter aplicações Java usando Java 11+.Trabalhar com Collections, Streams, Threads e conceitos de concorrência.Implementar soluções com Spring e AspectJ.Escrever testes automatizados com JUnit 5 e Mockito.Apoiar práticas de qualidade, observabilidade e análise de performance.RequisitosExperiência sólida com Java 11+ e desenvolvimento backend.Conhecimento de Spring, programação concorrente e ambiente Unix/Linux.Experiência com Docker, PostgreSQL e Liquibase.Familiaridade com Prometheus, ELK, Sonar e ferramentas de profiling como YourKit, JProfiler ou Visual VM.Conhecimento ou experiência com Kotlin.Ferramentas e tecnologiasJava 11+, Kotlin, Spring, AspectJ, JUnit 5, Mockito, Docker, PostgreSQL, Liquibase, Prometheus, ELK, Unix/Linux, Atlassian e Slack.\n","permalink":"https://kotlin.dev.br/vagas/j1cs7bj3e70ldkt8-devexperts-desenvolvedor-java-pleno-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Devexperts busca uma pessoa Desenvolvedora Java Pleno/Sênior para atuar em projetos backend, com modelo híbrido e base em São Paulo ou Brasil.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Java usando Java 11+.\u003c/li\u003e\u003cli\u003eTrabalhar com Collections, Streams, Threads e conceitos de concorrência.\u003c/li\u003e\u003cli\u003eImplementar soluções com Spring e AspectJ.\u003c/li\u003e\u003cli\u003eEscrever testes automatizados com JUnit 5 e Mockito.\u003c/li\u003e\u003cli\u003eApoiar práticas de qualidade, observabilidade e análise de performance.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sólida com Java 11+ e desenvolvimento backend.\u003c/li\u003e\u003cli\u003eConhecimento de Spring, programação concorrente e ambiente Unix/Linux.\u003c/li\u003e\u003cli\u003eExperiência com Docker, PostgreSQL e Liquibase.\u003c/li\u003e\u003cli\u003eFamiliaridade com Prometheus, ELK, Sonar e ferramentas de profiling como YourKit, JProfiler ou Visual VM.\u003c/li\u003e\u003cli\u003eConhecimento ou experiência com Kotlin.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFerramentas e tecnologias\u003c/h3\u003e\u003cp\u003eJava 11+, Kotlin, Spring, AspectJ, JUnit 5, Mockito, Docker, PostgreSQL, Liquibase, Prometheus, ELK, Unix/Linux, Atlassian e Slack.\u003c/p\u003e","title":"Desenvolvedor Java Pleno/Sênior"},{"content":"Sobre a vagaA Inter\u0026amp;Co busca uma pessoa Desenvolvedora de Software Especialista I para atuação com Android em Belo Horizonte, Minas Gerais, em modelo presencial.\nStack e práticasKotlin para desenvolvimento Android.Clean Architecture.Padrões MVVM e MVI.CI/CD.KMM e SDUI.PerfilNível pleno.Experiência em desenvolvimento mobile Android.Capacidade de atuar com arquitetura, padrões de apresentação e boas práticas de entrega contínua. ","permalink":"https://kotlin.dev.br/vagas/91o3hhp85rvtl33t-inter-co-desenvolvedor-a-android-especialista-i/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Inter\u0026amp;Co busca uma pessoa Desenvolvedora de Software Especialista I para atuação com Android em Belo Horizonte, Minas Gerais, em modelo presencial.\u003c/p\u003e\u003ch3\u003eStack e práticas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin para desenvolvimento Android.\u003c/li\u003e\u003cli\u003eClean Architecture.\u003c/li\u003e\u003cli\u003ePadrões MVVM e MVI.\u003c/li\u003e\u003cli\u003eCI/CD.\u003c/li\u003e\u003cli\u003eKMM e SDUI.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cul\u003e\u003cli\u003eNível pleno.\u003c/li\u003e\u003cli\u003eExperiência em desenvolvimento mobile Android.\u003c/li\u003e\u003cli\u003eCapacidade de atuar com arquitetura, padrões de apresentação e boas práticas de entrega contínua.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Android Especialista I"},{"content":"Sobre a vagaA SAP busca uma pessoa Desenvolvedora Full Stack Senior para atuar no produto SAP Concur Travel, em modelo híbrido em São Leopoldo, Rio Grande do Sul.\nStack e tecnologiasKotlin, Java, Go e Node.jsTypeScript, React, Redux, Express e WebpackGraphQL com Apollo ClientKubernetes e AWSFerramentas e recursos de IA como OpenAI, Anthropic, Copilot, Cline, Claude Code, LLM, MCP e RAGPerfilNível senior em desenvolvimento de software full stack.Experiência com desenvolvimento backend e frontend em ambientes modernos de produto.Disponibilidade para trabalho híbrido em São Leopoldo. ","permalink":"https://kotlin.dev.br/vagas/nho20zf76m8vhy7o-sap-desenvolvedor-a-full-stack-senior-sap-concur-travel/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA SAP busca uma pessoa Desenvolvedora Full Stack Senior para atuar no produto SAP Concur Travel, em modelo híbrido em São Leopoldo, Rio Grande do Sul.\u003c/p\u003e\u003ch3\u003eStack e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java, Go e Node.js\u003c/li\u003e\u003cli\u003eTypeScript, React, Redux, Express e Webpack\u003c/li\u003e\u003cli\u003eGraphQL com Apollo Client\u003c/li\u003e\u003cli\u003eKubernetes e AWS\u003c/li\u003e\u003cli\u003eFerramentas e recursos de IA como OpenAI, Anthropic, Copilot, Cline, Claude Code, LLM, MCP e RAG\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cul\u003e\u003cli\u003eNível senior em desenvolvimento de software full stack.\u003c/li\u003e\u003cli\u003eExperiência com desenvolvimento backend e frontend em ambientes modernos de produto.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho híbrido em São Leopoldo.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Full Stack Senior - SAP Concur Travel"},{"content":"Sobre a vagaA Airbnb busca uma pessoa Engenheira de Software de nível pleno para atuar na Plataforma de Qualidade, em posição remota no Brasil.\nTecnologias citadasKotlinTypeScriptSwiftJavaPythonCI/CDLLMsRAG (geração aumentada por recuperação)Informações disponíveisA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos ou benefícios.\n","permalink":"https://kotlin.dev.br/vagas/b4shnvovoy6hndue-airbnb-engenheiro-a-de-software-plataforma-de-qualidade/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Airbnb busca uma pessoa Engenheira de Software de nível pleno para atuar na Plataforma de Qualidade, em posição remota no Brasil.\u003c/p\u003e\u003ch3\u003eTecnologias citadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eTypeScript\u003c/li\u003e\u003cli\u003eSwift\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003ePython\u003c/li\u003e\u003cli\u003eCI/CD\u003c/li\u003e\u003cli\u003eLLMs\u003c/li\u003e\u003cli\u003eRAG (geração aumentada por recuperação)\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eInformações disponíveis\u003c/h3\u003e\u003cp\u003eA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos ou benefícios.\u003c/p\u003e","title":"Engenheiro(a) de Software, Plataforma de Qualidade"},{"content":"Sobre a vagaO C6 Bank busca uma Pessoa Desenvolvedora Backend Sênior Kotlin/Java para atuar na área de Cartões, em São Paulo, com modelo presencial.\nTecnologiasKotlinJavaSpring BootPostgreSQLMongoDBCassandraKafkaSQS e SNSRequisitosExperiência sênior em desenvolvimento Backend.Vivência com Kotlin e/ou Java.Experiência com Spring Boot.Conhecimento em bancos de dados relacionais e NoSQL.Experiência com mensageria e arquitetura orientada a eventos. ","permalink":"https://kotlin.dev.br/vagas/jsw60ydzqm7oruep-c6-bank-pessoa-desenvolvedora-backend-senior-kotlin-java-cartoe/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma Pessoa Desenvolvedora Backend Sênior Kotlin/Java para atuar na área de Cartões, em São Paulo, com modelo presencial.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eSpring Boot\u003c/li\u003e\u003cli\u003ePostgreSQL\u003c/li\u003e\u003cli\u003eMongoDB\u003c/li\u003e\u003cli\u003eCassandra\u003c/li\u003e\u003cli\u003eKafka\u003c/li\u003e\u003cli\u003eSQS e SNS\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Backend.\u003c/li\u003e\u003cli\u003eVivência com Kotlin e/ou Java.\u003c/li\u003e\u003cli\u003eExperiência com Spring Boot.\u003c/li\u003e\u003cli\u003eConhecimento em bancos de dados relacionais e NoSQL.\u003c/li\u003e\u003cli\u003eExperiência com mensageria e arquitetura orientada a eventos.\u003c/li\u003e\u003c/ul\u003e","title":"Pessoa Desenvolvedora Backend Sênior Kotlin/Java | Cartões"},{"content":"Sobre a vagaA Stone busca um(a) Engenheiro(a) de Software Android Sênior para atuação remota no Brasil.\nStack e contexto técnicoDesenvolvimento Android com Kotlin e Java.Uso de Gradle, WorkManager, ForegroundService e BroadcastReceiver.Projetos com KMP, Coroutines, Flows e Jetpack Compose.Integrações e comunicação de rede com OkHttpClient, UrlConnection e Ktor.Práticas com Git, CI/CD, Grafana, GCP e Looker Studio.Conhecimentos relacionados a AOSP e LLMs também aparecem no contexto da vaga.Senioridade e modelo de trabalhoNível: Sênior.Modelo: remoto.Localidade: Brasil. ","permalink":"https://kotlin.dev.br/vagas/8682mjglrdmwr0lf-stone-engenheiro-a-de-software-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Stone busca um(a) Engenheiro(a) de Software Android Sênior para atuação remota no Brasil.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolvimento Android com \u003cstrong\u003eKotlin\u003c/strong\u003e e Java.\u003c/li\u003e\u003cli\u003eUso de Gradle, WorkManager, ForegroundService e BroadcastReceiver.\u003c/li\u003e\u003cli\u003eProjetos com KMP, Coroutines, Flows e Jetpack Compose.\u003c/li\u003e\u003cli\u003eIntegrações e comunicação de rede com OkHttpClient, UrlConnection e Ktor.\u003c/li\u003e\u003cli\u003ePráticas com Git, CI/CD, Grafana, GCP e Looker Studio.\u003c/li\u003e\u003cli\u003eConhecimentos relacionados a AOSP e LLMs também aparecem no contexto da vaga.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade e modelo de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eNível: Sênior.\u003c/li\u003e\u003cli\u003eModelo: remoto.\u003c/li\u003e\u003cli\u003eLocalidade: Brasil.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Android Sênior"},{"content":"Sobre a vagaA Stone busca uma pessoa Engenheira de Software Android Sênior para atuação presencial em São Paulo, São Paulo.\nTecnologias informadasAndroid, Kotlin e JavaSDKs Android, Gradle, WorkManager, ForegroundService e BroadcastReceiverKMP, Coroutines/Flows e Jetpack ComposeOkHttpClient, UrlConnection e KtorGit, CI/CD, Grafana, GCP e Looker StudioAOSP e LLMsObservaçãoA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos ou benefícios.\n","permalink":"https://kotlin.dev.br/vagas/yrvjm1ai4922amhh-stone-engenheiro-a-de-software-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Stone busca uma pessoa \u003cstrong\u003eEngenheira de Software Android Sênior\u003c/strong\u003e para atuação presencial em São Paulo, São Paulo.\u003c/p\u003e\u003ch3\u003eTecnologias informadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAndroid, Kotlin e Java\u003c/li\u003e\u003cli\u003eSDKs Android, Gradle, WorkManager, ForegroundService e BroadcastReceiver\u003c/li\u003e\u003cli\u003eKMP, Coroutines/Flows e Jetpack Compose\u003c/li\u003e\u003cli\u003eOkHttpClient, UrlConnection e Ktor\u003c/li\u003e\u003cli\u003eGit, CI/CD, Grafana, GCP e Looker Studio\u003c/li\u003e\u003cli\u003eAOSP e LLMs\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eObservação\u003c/h3\u003e\u003cp\u003eA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos ou benefícios.\u003c/p\u003e","title":"Engenheiro(a) de Software Android Sênior"},{"content":"Sobre a vagaA Brex busca uma pessoa Engenheira de Software II para atuar em Backend, em modelo híbrido, com base em Seattle, Nova York, São Francisco ou São Paulo.\nStack e contexto técnicoKotlin e Java no backend.Micronaut para desenvolvimento de serviços.PostgreSQL como banco de dados relacional.Kafka para mensageria e processamento assíncrono.Integrações com Plaid, Finicity e Teller.React e TypeScript em interfaces e integrações quando necessário.RequisitosExperiência ou interesse sólido em desenvolvimento backend.Conhecimento em Kotlin, Java ou ecossistema JVM.Familiaridade com APIs, bancos relacionais e sistemas distribuídos.Disponibilidade para trabalho híbrido em uma das localidades informadas. ","permalink":"https://kotlin.dev.br/vagas/5xmjisv82msoj5e8-brex-engenheiro-a-de-software-ii-backend/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Brex busca uma pessoa Engenheira de Software II para atuar em Backend, em modelo híbrido, com base em Seattle, Nova York, São Francisco ou São Paulo.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Java no backend.\u003c/li\u003e\u003cli\u003eMicronaut para desenvolvimento de serviços.\u003c/li\u003e\u003cli\u003ePostgreSQL como banco de dados relacional.\u003c/li\u003e\u003cli\u003eKafka para mensageria e processamento assíncrono.\u003c/li\u003e\u003cli\u003eIntegrações com Plaid, Finicity e Teller.\u003c/li\u003e\u003cli\u003eReact e TypeScript em interfaces e integrações quando necessário.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência ou interesse sólido em desenvolvimento backend.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Java ou ecossistema JVM.\u003c/li\u003e\u003cli\u003eFamiliaridade com APIs, bancos relacionais e sistemas distribuídos.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho híbrido em uma das localidades informadas.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software II, Backend"},{"content":"Sobre a vagaA Brex busca um(a) Engenheiro(a) de Software II, Backend, em modelo híbrido, para atuar em uma das localidades: Nova York, São Francisco, São Paulo ou Seattle.\nTecnologiasKotlin e JavaMicronautPostgreSQLKafkaReact e TypeScriptIntegrações com Plaid, Finicity e TellerPerfilVaga de nível inicial para desenvolvimento backend, com atuação em sistemas e integrações usando tecnologias JVM e serviços de dados.\n","permalink":"https://kotlin.dev.br/vagas/ow5b6xi4sursige0-brex-engenheiro-a-de-software-ii-backend/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Brex busca um(a) Engenheiro(a) de Software II, Backend, em modelo híbrido, para atuar em uma das localidades: Nova York, São Francisco, São Paulo ou Seattle.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Java\u003c/li\u003e\u003cli\u003eMicronaut\u003c/li\u003e\u003cli\u003ePostgreSQL\u003c/li\u003e\u003cli\u003eKafka\u003c/li\u003e\u003cli\u003eReact e TypeScript\u003c/li\u003e\u003cli\u003eIntegrações com Plaid, Finicity e Teller\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cp\u003eVaga de nível inicial para desenvolvimento backend, com atuação em sistemas e integrações usando tecnologias JVM e serviços de dados.\u003c/p\u003e","title":"Engenheiro(a) de Software II, Backend"},{"content":"Sobre a vagaA Brex busca uma pessoa Engenheira de Software II, Backend, para atuar em modelo híbrido em San Francisco, Nova York, São Paulo ou Seattle.\nTecnologiasKotlin e Java no backendMicronautPostgreSQLKafkaIntegrações com Plaid, Finicity e TellerReact e TypeScriptPerfilVaga de nível inicial para desenvolvimento de software backend. A descrição original não detalha responsabilidades, requisitos específicos ou benefícios.\n","permalink":"https://kotlin.dev.br/vagas/t0wd1onb2lz7phr0-brex-engenheiro-a-de-software-ii-backend/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Brex busca uma pessoa Engenheira de Software II, Backend, para atuar em modelo híbrido em San Francisco, Nova York, São Paulo ou Seattle.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Java no backend\u003c/li\u003e\u003cli\u003eMicronaut\u003c/li\u003e\u003cli\u003ePostgreSQL\u003c/li\u003e\u003cli\u003eKafka\u003c/li\u003e\u003cli\u003eIntegrações com Plaid, Finicity e Teller\u003c/li\u003e\u003cli\u003eReact e TypeScript\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cp\u003eVaga de nível inicial para desenvolvimento de software backend. A descrição original não detalha responsabilidades, requisitos específicos ou benefícios.\u003c/p\u003e","title":"Engenheiro(a) de Software II, Backend"},{"content":"Sobre a vagaA Zup Innovation busca uma Pessoa Desenvolvedora Mobile Especialista para atuação remota em um contexto sênior de desenvolvimento Android com Java e Kotlin.\nRequisitos e tecnologiasExperiência sênior com desenvolvimento Mobile Android.Conhecimento em Kotlin e Java.Arquitetura e padrões como MVVM, StateFlow e Navigation Graph.Experiência com Jetpack Compose, Logcat, Crashlytics e Remote Config.Uso de Gradle, ProGuard e R8.Vivência com Git, CI/CD, App Distribution, Play Store e Fastlane.Modelo de trabalhoVaga remota, associada à localização de São Paulo, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/wikuypusr5lsis9c-zup-innovation-pessoa-desenvolvedora-mobile-especialista-java-k/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Zup Innovation busca uma Pessoa Desenvolvedora Mobile Especialista para atuação remota em um contexto sênior de desenvolvimento Android com Java e Kotlin.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com desenvolvimento Mobile Android.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eJava\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eArquitetura e padrões como \u003cstrong\u003eMVVM\u003c/strong\u003e, \u003cstrong\u003eStateFlow\u003c/strong\u003e e \u003cstrong\u003eNavigation Graph\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eJetpack Compose\u003c/strong\u003e, Logcat, Crashlytics e Remote Config.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eGradle\u003c/strong\u003e, ProGuard e R8.\u003c/li\u003e\u003cli\u003eVivência com Git, CI/CD, App Distribution, Play Store e Fastlane.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota, associada à localização de São Paulo, São Paulo, Brasil.\u003c/p\u003e","title":"Pessoa Desenvolvedora Mobile Especialista (Java/Kotlin)"},{"content":"Sobre a vagaO Albert Einstein busca uma pessoa Tech Lead - Especialista em Sistemas para atuar no Desenvolvimento Meu Einstein, em modelo híbrido na região da Faria Lima, em São Paulo.\nStack e contexto técnicoMobile e front-end: Kotlin, Swift, Flutter, React Native, Redux, MobX e Zustand.Backend e integrações: Node.js, TypeScript, GraphQL, Kafka e RabbitMQ.Dados: PostgreSQL, MySQL e MongoDB.DevOps e observabilidade: Microsoft Azure DevOps, GitHub Actions, Docker, Kubernetes, Dynatrace, Git e CI/CD.Arquitetura e qualidade: Clean Architecture, MVVM, Firebase Crashlytics e GitHub Copilot.RequisitosExperiência sênior em liderança técnica de sistemas.Vivência com desenvolvimento de produtos digitais e aplicativos mobile.Conhecimento em arquitetura, integração de sistemas, pipelines CI/CD e práticas modernas de engenharia.Local de trabalhoSão Paulo, São Paulo, Brasil. Modelo híbrido.\n","permalink":"https://kotlin.dev.br/vagas/jmk3ps6gvhly8ev2-albert-einstein-tech-lead-especialista-em-sistemas/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO Albert Einstein busca uma pessoa Tech Lead - Especialista em Sistemas para atuar no Desenvolvimento Meu Einstein, em modelo híbrido na região da Faria Lima, em São Paulo.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eMobile e front-end: \u003cstrong\u003eKotlin\u003c/strong\u003e, Swift, Flutter, React Native, Redux, MobX e Zustand.\u003c/li\u003e\u003cli\u003eBackend e integrações: Node.js, TypeScript, GraphQL, Kafka e RabbitMQ.\u003c/li\u003e\u003cli\u003eDados: PostgreSQL, MySQL e MongoDB.\u003c/li\u003e\u003cli\u003eDevOps e observabilidade: Microsoft Azure DevOps, GitHub Actions, Docker, Kubernetes, Dynatrace, Git e CI/CD.\u003c/li\u003e\u003cli\u003eArquitetura e qualidade: Clean Architecture, MVVM, Firebase Crashlytics e GitHub Copilot.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em liderança técnica de sistemas.\u003c/li\u003e\u003cli\u003eVivência com desenvolvimento de produtos digitais e aplicativos mobile.\u003c/li\u003e\u003cli\u003eConhecimento em arquitetura, integração de sistemas, pipelines CI/CD e práticas modernas de engenharia.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eSão Paulo, São Paulo, Brasil. Modelo híbrido.\u003c/p\u003e","title":"Tech Lead - Especialista em Sistemas"},{"content":"Sobre a vagaA AB InBev busca uma pessoa Desenvolvedora Backend Pleno para atuação presencial em Campinas, São Paulo.\nStack e contexto técnicoA posição envolve desenvolvimento backend com Java, Kotlin e Spring Boot, além de integração com bancos de dados relacionais e NoSQL, mensageria, cloud e ferramentas de observabilidade.\nRequisitosExperiência em desenvolvimento backend com Java, Kotlin e Spring Boot.Conhecimento em bancos de dados como PostgreSQL, MySQL, SQL Server, MongoDB e Redis.Experiência com mensageria usando Kafka ou RabbitMQ.Familiaridade com Git, Docker e Kubernetes.Conhecimento em cloud e infraestrutura como código, incluindo AWS, Azure, GCP, Terraform ou CloudFormation.Vivência com ferramentas de observabilidade como New Relic, Datadog, Grafana ou Prometheus.Local de trabalhoAtuação presencial em Campinas, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/bmdokr58qcgfmmcp-ab-inbev-desenvolvedor-backend-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA AB InBev busca uma pessoa Desenvolvedora Backend Pleno para atuação presencial em Campinas, São Paulo.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cp\u003eA posição envolve desenvolvimento backend com Java, Kotlin e Spring Boot, além de integração com bancos de dados relacionais e NoSQL, mensageria, cloud e ferramentas de observabilidade.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento backend com Java, Kotlin e Spring Boot.\u003c/li\u003e\u003cli\u003eConhecimento em bancos de dados como PostgreSQL, MySQL, SQL Server, MongoDB e Redis.\u003c/li\u003e\u003cli\u003eExperiência com mensageria usando Kafka ou RabbitMQ.\u003c/li\u003e\u003cli\u003eFamiliaridade com Git, Docker e Kubernetes.\u003c/li\u003e\u003cli\u003eConhecimento em cloud e infraestrutura como código, incluindo AWS, Azure, GCP, Terraform ou CloudFormation.\u003c/li\u003e\u003cli\u003eVivência com ferramentas de observabilidade como New Relic, Datadog, Grafana ou Prometheus.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eAtuação presencial em Campinas, São Paulo, Brasil.\u003c/p\u003e","title":"Desenvolvedor Backend Pleno"},{"content":"Sobre a vagaA AB InBev busca uma pessoa Desenvolvedora Backend Pleno para atuação presencial em Campinas, São Paulo, com foco em desenvolvimento backend usando Kotlin, Java e Spring Boot.\nResponsabilidadesDesenvolver e manter serviços backend e APIs RESTful.Trabalhar com integrações, mensageria e persistência de dados.Colaborar com práticas de CI/CD, observabilidade e infraestrutura em nuvem.RequisitosExperiência com Java, Kotlin, Spring e Spring Boot.Conhecimento em APIs RESTful.Experiência com bancos relacionais como PostgreSQL, MySQL ou SQL Server.Conhecimento em mensageria com Kafka ou RabbitMQ.Familiaridade com Git, Docker e Kubernetes.Tecnologias relacionadasBancos e cache: MongoDB, Redis, PostgreSQL, MySQL e SQL Server.Cloud e infraestrutura: AWS, Azure, GCP, Terraform e CloudFormation.Observabilidade: New Relic, Datadog, Grafana e Prometheus.Outras tecnologias: Python e pipelines de CI/CD. ","permalink":"https://kotlin.dev.br/vagas/lhualnys4aalpuzq-ab-inbev-desenvolvedor-backend-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA AB InBev busca uma pessoa Desenvolvedora Backend Pleno para atuação presencial em Campinas, São Paulo, com foco em desenvolvimento backend usando Kotlin, Java e Spring Boot.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend e APIs RESTful.\u003c/li\u003e\u003cli\u003eTrabalhar com integrações, mensageria e persistência de dados.\u003c/li\u003e\u003cli\u003eColaborar com práticas de CI/CD, observabilidade e infraestrutura em nuvem.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Java, Kotlin, Spring e Spring Boot.\u003c/li\u003e\u003cli\u003eConhecimento em APIs RESTful.\u003c/li\u003e\u003cli\u003eExperiência com bancos relacionais como PostgreSQL, MySQL ou SQL Server.\u003c/li\u003e\u003cli\u003eConhecimento em mensageria com Kafka ou RabbitMQ.\u003c/li\u003e\u003cli\u003eFamiliaridade com Git, Docker e Kubernetes.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias relacionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eBancos e cache: MongoDB, Redis, PostgreSQL, MySQL e SQL Server.\u003c/li\u003e\u003cli\u003eCloud e infraestrutura: AWS, Azure, GCP, Terraform e CloudFormation.\u003c/li\u003e\u003cli\u003eObservabilidade: New Relic, Datadog, Grafana e Prometheus.\u003c/li\u003e\u003cli\u003eOutras tecnologias: Python e pipelines de CI/CD.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Backend Pleno"},{"content":"Sobre a vagaA Devexperts busca uma pessoa Desenvolvedora Java Pleno/Sênior para atuar em modelo híbrido, com base em São Paulo ou Brasil.\nStack e ferramentasJava 11+, Collections, Streams, Threads e ConcorrênciaSpring, AspectJ e KotlinJUnit 5 e MockitoDocker, PostgreSQL e LiquibasePrometheus, ELK, YourKit, JProfiler e VisualVMAtlassian, Slack, Sonar e Unix/LinuxRequisitosExperiência em desenvolvimento Java em nível pleno ou sênior.Conhecimento de concorrência, threads e boas práticas de desenvolvimento backend.Familiaridade com testes automatizados, bancos relacionais e ferramentas de observabilidade. ","permalink":"https://kotlin.dev.br/vagas/g80ztyqambfw8ibu-devexperts-desenvolvedor-java-pleno-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Devexperts busca uma pessoa Desenvolvedora Java Pleno/Sênior para atuar em modelo híbrido, com base em São Paulo ou Brasil.\u003c/p\u003e\u003ch3\u003eStack e ferramentas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eJava 11+, Collections, Streams, Threads e Concorrência\u003c/li\u003e\u003cli\u003eSpring, AspectJ e Kotlin\u003c/li\u003e\u003cli\u003eJUnit 5 e Mockito\u003c/li\u003e\u003cli\u003eDocker, PostgreSQL e Liquibase\u003c/li\u003e\u003cli\u003ePrometheus, ELK, YourKit, JProfiler e VisualVM\u003c/li\u003e\u003cli\u003eAtlassian, Slack, Sonar e Unix/Linux\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento Java em nível pleno ou sênior.\u003c/li\u003e\u003cli\u003eConhecimento de concorrência, threads e boas práticas de desenvolvimento backend.\u003c/li\u003e\u003cli\u003eFamiliaridade com testes automatizados, bancos relacionais e ferramentas de observabilidade.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Java Pleno/Sênior"},{"content":"Sobre a vagaA CI\u0026T busca uma pessoa Desenvolvedora Android Master para atuação remota no Brasil, com foco em desenvolvimento mobile sênior.\nRequisitosExperiência avançada em desenvolvimento Android com Kotlin.Conhecimento em Kotlin Multiplatform e integração com ecossistemas mobile.Experiência com arquitetura mobile, incluindo Clean Architecture, MVVM e MVI.Vivência com práticas de CI/CD e DevSecOps.Conhecimento em Swift para colaboração em soluções multiplataforma.Experiência ou familiaridade com SDUI.Modelo de trabalhoVaga remota para profissionais no Brasil.\n","permalink":"https://kotlin.dev.br/vagas/ahfl2ks3gbsbzqjd-ci-t-desenvolvedor-a-android-master/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T busca uma pessoa Desenvolvedora Android Master para atuação remota no Brasil, com foco em desenvolvimento mobile sênior.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência avançada em desenvolvimento Android com \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin Multiplatform\u003c/strong\u003e e integração com ecossistemas mobile.\u003c/li\u003e\u003cli\u003eExperiência com arquitetura mobile, incluindo \u003cstrong\u003eClean Architecture\u003c/strong\u003e, \u003cstrong\u003eMVVM\u003c/strong\u003e e \u003cstrong\u003eMVI\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com práticas de \u003cstrong\u003eCI/CD\u003c/strong\u003e e \u003cstrong\u003eDevSecOps\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eSwift\u003c/strong\u003e para colaboração em soluções multiplataforma.\u003c/li\u003e\u003cli\u003eExperiência ou familiaridade com \u003cstrong\u003eSDUI\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais no Brasil.\u003c/p\u003e","title":"Desenvolvedor(a) Android Master"},{"content":"Sobre a vagaA Partner One busca uma pessoa Engenheiro(a) de Middleware Sênior para atuação remota na Bolívia ou em outros países da América do Sul.\nA posição é focada em middleware, mensageria, integrações, observabilidade e infraestrutura para ambientes distribuídos.\nTecnologias mencionadasLinguagens: C#, Java, Kotlin, Python e Go.Mensageria e eventos: RabbitMQ, Apache Kafka, Azure Service Bus, Azure Event Hubs, Azure Event Grid, Redis Streams e Azure Cache for Redis.Integração: Apache Camel, MuleSoft, Azure Integration Services, Azure Logic Apps, Azure Functions e APIM.Infraestrutura e plataforma: Kubernetes, Helm, Terraform, Bicep, Ansible, Istio, Linkerd e Azure Service Mesh.Observabilidade e segurança: OpenTelemetry, Prometheus, Grafana, Azure Key Vault e HashiCorp Vault.Formatos e contratos: Avro, Protobuf e JSON.RequisitosExperiência sênior em engenharia de middleware ou integração de sistemas.Vivência com arquitetura orientada a eventos, filas, streams e serviços distribuídos.Conhecimento prático em Kubernetes e automação de infraestrutura.Experiência com observabilidade, segurança de segredos e operação de ambientes em nuvem. ","permalink":"https://kotlin.dev.br/vagas/h6crf51xwi3smc2x-partner-one-engenheiro-a-de-middleware-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Partner One busca uma pessoa Engenheiro(a) de Middleware Sênior para atuação remota na Bolívia ou em outros países da América do Sul.\u003c/p\u003e\u003cp\u003eA posição é focada em middleware, mensageria, integrações, observabilidade e infraestrutura para ambientes distribuídos.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLinguagens: C#, Java, Kotlin, Python e Go.\u003c/li\u003e\u003cli\u003eMensageria e eventos: RabbitMQ, Apache Kafka, Azure Service Bus, Azure Event Hubs, Azure Event Grid, Redis Streams e Azure Cache for Redis.\u003c/li\u003e\u003cli\u003eIntegração: Apache Camel, MuleSoft, Azure Integration Services, Azure Logic Apps, Azure Functions e APIM.\u003c/li\u003e\u003cli\u003eInfraestrutura e plataforma: Kubernetes, Helm, Terraform, Bicep, Ansible, Istio, Linkerd e Azure Service Mesh.\u003c/li\u003e\u003cli\u003eObservabilidade e segurança: OpenTelemetry, Prometheus, Grafana, Azure Key Vault e HashiCorp Vault.\u003c/li\u003e\u003cli\u003eFormatos e contratos: Avro, Protobuf e JSON.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de middleware ou integração de sistemas.\u003c/li\u003e\u003cli\u003eVivência com arquitetura orientada a eventos, filas, streams e serviços distribuídos.\u003c/li\u003e\u003cli\u003eConhecimento prático em Kubernetes e automação de infraestrutura.\u003c/li\u003e\u003cli\u003eExperiência com observabilidade, segurança de segredos e operação de ambientes em nuvem.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Middleware Sênior"},{"content":"Sobre a vagaA Airbnb busca uma pessoa Engenheira de Software Android Sênior para atuar na Plataforma de Qualidade, em modelo remoto no Brasil.\nResponsabilidadesAtuar em iniciativas de qualidade para aplicações Android.Contribuir com ferramentas, automação e processos de CI/CD.Colaborar com equipes multidisciplinares para melhorar confiabilidade, testes e experiência de desenvolvimento.RequisitosExperiência sênior em desenvolvimento de software.Experiência com Android e Kotlin.Conhecimento de Java, Python, Swift ou TypeScript.Vivência com práticas de qualidade de software, automação e pipelines de CI/CD.DiferenciaisExperiência com LLMs e Retrieval-Augmented Generation (RAG).Experiência em plataformas internas, ferramentas de desenvolvedor ou infraestrutura de qualidade. ","permalink":"https://kotlin.dev.br/vagas/tcbac78qba6jhiqa-airbnb-engenheiro-a-de-software-android-senior-plataforma-de-qu/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Airbnb busca uma pessoa Engenheira de Software Android Sênior para atuar na Plataforma de Qualidade, em modelo remoto no Brasil.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAtuar em iniciativas de qualidade para aplicações Android.\u003c/li\u003e\u003cli\u003eContribuir com ferramentas, automação e processos de CI/CD.\u003c/li\u003e\u003cli\u003eColaborar com equipes multidisciplinares para melhorar confiabilidade, testes e experiência de desenvolvimento.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento de software.\u003c/li\u003e\u003cli\u003eExperiência com Android e Kotlin.\u003c/li\u003e\u003cli\u003eConhecimento de Java, Python, Swift ou TypeScript.\u003c/li\u003e\u003cli\u003eVivência com práticas de qualidade de software, automação e pipelines de CI/CD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com LLMs e Retrieval-Augmented Generation (RAG).\u003c/li\u003e\u003cli\u003eExperiência em plataformas internas, ferramentas de desenvolvedor ou infraestrutura de qualidade.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Android Sênior, Plataforma de Qualidade"},{"content":"Sobre a vagaO QuintoAndar busca uma pessoa Engenheira de Software Sênior para atuar em Corporate Engineering, em modelo híbrido, com base no Brasil ou em São Paulo.\nStack e contexto técnicoKotlin, Java, JavaScript e Python.Ambientes cloud com AWS, GCP e Azure.Kubernetes e práticas de CI/CD.Integrações e automações com Google Workspace, HRIS e soluções SaaS.SenioridadeVaga de nível sênior, voltada a profissionais com experiência em engenharia de software e sistemas corporativos.\n","permalink":"https://kotlin.dev.br/vagas/bpbdz6eerenc1ax3-quintoandar-engenheiro-a-de-software-senior-corporate-engineeri/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO QuintoAndar busca uma pessoa Engenheira de Software Sênior para atuar em Corporate Engineering, em modelo híbrido, com base no Brasil ou em São Paulo.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java, JavaScript e Python.\u003c/li\u003e\u003cli\u003eAmbientes cloud com AWS, GCP e Azure.\u003c/li\u003e\u003cli\u003eKubernetes e práticas de CI/CD.\u003c/li\u003e\u003cli\u003eIntegrações e automações com Google Workspace, HRIS e soluções SaaS.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade\u003c/h3\u003e\u003cp\u003eVaga de nível sênior, voltada a profissionais com experiência em engenharia de software e sistemas corporativos.\u003c/p\u003e","title":"Engenheiro(a) de Software Sênior - Corporate Engineering"},{"content":"Sobre a vagaA Partner One busca uma pessoa Engenheiro(a) Middleware Sênior para atuar remotamente em projetos de integração, mensageria e infraestrutura em nuvem.\nStack e contexto técnicoMensageria e streaming com RabbitMQ, Apache Kafka, Azure Service Bus, Azure Event Grid e Azure Event Hubs.Cache e dados com Redis e Azure Cache for Redis.Integrações com Azure Logic Apps, Azure Functions, APIM, Apache Camel e MuleSoft.Infraestrutura e plataforma com Kubernetes, Helm, Terraform, Bicep e Ansible.Observabilidade com OpenTelemetry, Prometheus e Grafana.Segurança e segredos com Azure Key Vault e HashiCorp Vault.Linguagens e formatos como Kotlin, Java, C# (.NET), Python, Go, JSON, Avro e Protobuf.RequisitosExperiência sênior em middleware, integração de sistemas, APIs ou plataformas orientadas a eventos.Vivência com ambientes cloud, automação de infraestrutura e operação de serviços distribuídos.Disponibilidade para atuação remota a partir do Uruguai ou da América do Sul. ","permalink":"https://kotlin.dev.br/vagas/9s82a9gjh4zii4al-partner-one-engenheiro-a-middleware-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Partner One busca uma pessoa Engenheiro(a) Middleware Sênior para atuar remotamente em projetos de integração, mensageria e infraestrutura em nuvem.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eMensageria e streaming com RabbitMQ, Apache Kafka, Azure Service Bus, Azure Event Grid e Azure Event Hubs.\u003c/li\u003e\u003cli\u003eCache e dados com Redis e Azure Cache for Redis.\u003c/li\u003e\u003cli\u003eIntegrações com Azure Logic Apps, Azure Functions, APIM, Apache Camel e MuleSoft.\u003c/li\u003e\u003cli\u003eInfraestrutura e plataforma com Kubernetes, Helm, Terraform, Bicep e Ansible.\u003c/li\u003e\u003cli\u003eObservabilidade com OpenTelemetry, Prometheus e Grafana.\u003c/li\u003e\u003cli\u003eSegurança e segredos com Azure Key Vault e HashiCorp Vault.\u003c/li\u003e\u003cli\u003eLinguagens e formatos como Kotlin, Java, C# (.NET), Python, Go, JSON, Avro e Protobuf.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em middleware, integração de sistemas, APIs ou plataformas orientadas a eventos.\u003c/li\u003e\u003cli\u003eVivência com ambientes cloud, automação de infraestrutura e operação de serviços distribuídos.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação remota a partir do Uruguai ou da América do Sul.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) Middleware Sênior"},{"content":"Recomposição desnecessária é o problema de performance número um em apps Jetpack Compose em produção. O sintoma é clássico: a UI engasga, lista trava em scroll, mas o profiler não mostra nada óbvio — porque a causa raiz raramente é \u0026ldquo;código lento\u0026rdquo; e quase sempre é o Compose Compiler classificando como instável uma classe que deveria ser estável. Em 2026, com o Compose Compiler 1.6+ integrado ao Kotlin 2.2+, o Configurador de Estabilidade (Stability Configurator) e o arquivo stability_config.conf se tornaram a ferramenta oficial para corrigir esse problema sem espalhar anotações pelo código.\nNeste guia você configura o estabilidade do Compose corretamente, do diagnóstico ao fix, com Kotlin 2.2 e Compose BOM 2026. Se você ainda não dominou os fundamentos de recomposição, vale revisar antes o guia de Jetpack Compose e o guia de performance em Kotlin, porque este artigo pressupõe que você já sabe o que é slot table e quando o Compose decide recompor.\n1. Por que estabilidade importa O Compose decide se um composable vai recompor comparando os parâmetros da chamada atual com a anterior. Para isso funcionar de forma barata, o compilador marca cada parâmetro como estável ou instável:\nEstável: o tipo pode ser comparado por igualdade estrutural e o Compose confia que, se os parâmetros não mudaram, a recomposição é segura de pular. Instável: o Compose não consegue provar que o valor não mudou, então recomputa sempre. A consequência prática é direta: um único parâmetro instável em um composable grande força a recomposição inteira dele e de todos os filhos que não estiverem protegidos por uma chave explícita. Em uma lista com 50 itens, isso vira jank visível.\nA regra clássica do compilador é simples, mas restritiva:\nTipos primitivos (Int, String, Boolean) são estáveis. Tipos val-only com campos estáveis e declarados como data class são estáveis. Tipos com pelo menos um var ou com um campo de tipo instável (como List, Set, Map da kotlin.collections) são marcados como instáveis, mesmo que você nunca os muta. É essa última regra que causa a maioria dos problemas reais. Uma data class imutável que contém List\u0026lt;String\u0026gt; é instável para o compilador, porque List é uma interface que pode ter uma implementação mutável (MutableList) por baixo.\n2. Diagnóstico: ativando o relatório de estabilidade Antes de mexer em nada, ative o relatório do Compose Compiler para ver exatamente quais classes estão instáveis e quais composables estão recompondo demais. No build.gradle.kts do módulo:\nandroid { composeCompiler { // Kotlin 2.2+: use a extensão composeCompiler do plugin reportsDestination = layout.buildDirectory.dir(\u0026#34;compose_compiler\u0026#34;) metricsDestination = layout.buildDirectory.dir(\u0026#34;compose_compiler\u0026#34;) } } Após um ./gradlew :app:assembleDebug, abra app/build/compose_compiler/*-classes.txt. Cada classe aparece assim:\nstable class MinhaDataClassImutavel { val nome: String val idade: Int } unstable class MinhaListaClass { val itens: List\u0026lt;String\u0026gt; // \u0026lt;-- instável porque List é instável } O arquivo *-composables.txt mostra, para cada composable, se ele é restartable, skippable e quais parâmetros são instáveis. Um composable restartable mas não skippable com parâmetro instável é o seu alvo de otimização.\n3. Solução clássica: @Immutable e @Stable A correção mais antiga (e ainda válida) é anotar a classe. O artigo sobre data classes e sealed classes em Kotlin cobre o design delas em profundidade; aqui o foco é a anotação de estabilidade.\nimport androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable @Immutable data class EstadoTela( val itens: List\u0026lt;String\u0026gt;, // agora tratada como estável val selecionado: Boolean ) @Stable class ViewModelHolder(val estado: StateFlow\u0026lt;EstadoTela\u0026gt;) A diferença entre as duas anotações:\n@Immutable: você garante que nenhum campo muda após a construção. Se você mentir (um var mutável por baixo), o Compose vai exibir UI inconsistente. Use só em classes realmente imutáveis. @Stable: a classe pode mudar, mas você garante que notifica o Compose (MutableState, StateFlow coletado como State, etc.). É o caso típico de wrappers de ViewModel. O problema dessa abordagem é que ela espalha dependência do androidx.compose.runtime por módulos que não deveriam conhecer Compose (camada de domínio, de dados). É aí que entra o Configurador de Estabilidade.\n4. Configurador de Estabilidade (stability_config.conf) Desde o Compose Compiler 1.5.4 (e refinado até o 1.6.x de 2026), você pode declarar tipos estáveis em um arquivo de configuração, sem anotar o código-fonte. Crie compose-stability.conf na raiz do módulo:\n// Considera estas classes estáveis para o Compose, sem anotação no código java.time.Duration java.time.Instant java.time.LocalDate java.util.UUID kotlin.coroutines.CoroutineContext // Pacote inteiro da camada de modelo pode ser marcado como estável com.meuapp.modelo.* E referencie no build.gradle.kts:\nandroid { composeCompiler { stabilityConfigurationFile = project.layout.projectDirectory.file(\u0026#34;compose-stability.conf\u0026#34;) } } As regras aceitas no arquivo são:\nNome totalmente qualificado de uma classe: com.meuapp.modelo.Usuario. Pacote curinga: com.meuapp.modelo.* (cobre todos os tipos do pacote, recursivamente em subpacotes com com.meuapp.modelo.**). Comentários com # ou //. Isso resolve o caso mais comum: você tem uma camada de modelo data class pura (sem var, sem MutableList) que o compilador marca como instável só porque contém List. Marcando o pacote como estável, todo o modelo passa a ser skippable sem poluir o código de domínio com anotação Android.\n5. Caso prático: lista que travava no scroll Considere um caso real. Você tem:\ndata class Produto( val id: String, val nome: String, val tags: List\u0026lt;String\u0026gt; // \u0026lt;-- torna a classe instável ) @Composable fun ListaProdutos(produtos: List\u0026lt;Produto\u0026gt;) { LazyColumn { items(produtos, key = { it.id }) { produto -\u0026gt; ItemProduto(produto) // recomputa a cada scroll por causa do tipo instável } } } @Composable fun ItemProduto(produto: Produto) { // ... } Sem correção, o relatório mostra ItemProduto como restartable mas não skippable. A correção mínima é adicionar ao compose-stability.conf:\ncom.meuapp.modelo.* Rode novamente o build, regenere o relatório e confirme que ItemProduto agora aparece como skippable. O efeito em uma lista de 50 itens costuma ser uma queda de 30 a 60% no tempo de recomposição medido pelo Macrobenchmark, porque o Compose passa a pular recomposições de itens que não mudaram.\n6. Armadilhas comuns 6.1. List, Set, Map da kotlin.collections Mesmo com @Immutable na classe que as contém, o compilador em algumas versões ainda reclama. A forma mais robusta em 2026 é usar o configurador no pacote do modelo, ou converter para tipos imutáveis do KotlinX (ImmutableList, PersistentList via kotlinx.collections.immutable), que o compilador reconhece como estáveis nativamente.\nimport kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf data class Carrinho(val itens: ImmutableList\u0026lt;Produto\u0026gt; = persistentListOf()) 6.2. Classes com List mutada internamente Não minta para o compilador. Se você marcar uma classe como @Immutable mas mutar a lista por referência externa, o Compose não vai recompor quando deveria e a UI fica dessincronizada. Nesse caso, use @Stable com MutableState ou migre para ImmutableList.\n6.3. Lambdas capturando estado Um composable com parâmetro lambda (Produto) -\u0026gt; Unit é estável, mas se o lambda captura um var externo, a instabilidade volta pela porta dos fundos. Use remember { { produto -\u0026gt; ... } } ou extraia o estado para um rememberSaveable. Isso conecta com o padrão discutido no guia de Flow e StateFlow — o estado observável sempre deve vir de uma fonte estável.\n6.4. ViewModel como parâmetro Passar o ViewModel inteiro como parâmetro de composable deixa tudo instável. Extraia o estado em uma data class imutável e observe com collectAsStateWithLifecycle(). Veja o guia de arquitetura MVVM em Kotlin para o padrão de UI state.\n7. Medindo o ganho com Macrobenchmark Depois de aplicar o configurador, meça com Macrobenchmark para confirmar o ganho real, não só o relatório do compilador. Um benchmark de scroll típico:\n@Test fun scrollListaProdutos() = benchmarkRule.measureRepeated( packageName = \u0026#34;com.meuapp\u0026#34;, metrics = listOf(FrameTimingMetric()) ) { startActivityAndWait() val lista = device.findObject(By.res(\u0026#34;lista_produtos\u0026#34;)) device.scrollUntilFound(lista, UiScrollable.Direction.DOWN, 20) } Compare o frameDurationCpuMs P95 antes e depois. Reduções de 8-10ms para 4-5ms são comuns quando a causa raiz era instabilidade de parâmetro. Combine com o guia de Baseline Profiles para o ganho cumulativo.\n8. Checklist final Antes de fechar um PR de otimização de estabilidade:\nRode ./gradlew :app:assembleDebug e abra *-classes.txt — confirme que as classes-alvo viraram stable. Abra *-composables.txt — confirme que os composables afetados viraram skippable. Escreva um Macrobenchmark de scroll e compare P95 de frameDurationCpuMs. Verifique que nenhum @Immutable está mentindo (grep por var em classes anotadas). Documente no compose-stability.conf por que cada pacote foi marcado — um comentário por linha economiza debug futuro. Conclusão O Configurador de Estabilidade é o investimento de maior ROI em performance de Compose para apps médios e grandes em 2026. Ele resolve na origem o problema de recomposição desnecessária sem acoplar a camada de domínio ao runtime do Compose, e o ganho é mensurável com as ferramentas que você já tem no build. A regra prática: se o relatório do compilador mostra uma data class pura marcada como unstable, o stability_config.conf é quase sempre a resposta certa.\nPara aprofundar, combine este guia com o de Baseline Profiles e Macrobenchmark, o de Material 3 Expressive (que também depende de parâmetros estáveis para animar bem) e o guia de testes em Kotlin para validar o comportamento da UI após a mudança.\n","permalink":"https://kotlin.dev.br/blog/configurador-estabilidade-compose-kotlin-2026/","summary":"\u003cp\u003eRecomposição desnecessária é o problema de performance número um em apps Jetpack Compose em produção. O sintoma é clássico: a UI engasga, lista trava em scroll, mas o profiler não mostra nada óbvio — porque a causa raiz raramente é \u0026ldquo;código lento\u0026rdquo; e quase sempre é o \u003cstrong\u003eCompose Compiler classificando como instável uma classe que deveria ser estável\u003c/strong\u003e. Em 2026, com o Compose Compiler 1.6+ integrado ao Kotlin 2.2+, o \u003cstrong\u003eConfigurador de Estabilidade\u003c/strong\u003e (Stability Configurator) e o arquivo \u003ccode\u003estability_config.conf\u003c/code\u003e se tornaram a ferramenta oficial para corrigir esse problema sem espalhar anotações pelo código.\u003c/p\u003e","title":"Configurador de Estabilidade do Compose: guia completo com Kotlin em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA Hiflylabs busca uma pessoa Arquiteta de Soluções sênior para aplicações de IA e dados, em modelo híbrido em Blumenau, Santa Catarina.\nStack citadaKotlin, Swift, Java, Python, Node.js, Angular e React.Databricks, Lakebase, MLflow e Unity Catalog.LangChain, AutoGen, FastAPI, Docker e CI/CD.RequisitosExperiência sênior em arquitetura de soluções para aplicações de IA, dados e software.Conhecimento em desenvolvimento mobile, web e backend com as tecnologias listadas.Disponibilidade para trabalho híbrido em Blumenau. ","permalink":"https://kotlin.dev.br/vagas/9mm5hmfjh4ykjyy3-hiflylabs-arquiteto-de-solucoes-aplicacoes-de-ia-e-dados/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Hiflylabs busca uma pessoa Arquiteta de Soluções sênior para aplicações de IA e dados, em modelo híbrido em Blumenau, Santa Catarina.\u003c/p\u003e\u003ch3\u003eStack citada\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Swift, Java, Python, Node.js, Angular e React.\u003c/li\u003e\u003cli\u003eDatabricks, Lakebase, MLflow e Unity Catalog.\u003c/li\u003e\u003cli\u003eLangChain, AutoGen, FastAPI, Docker e CI/CD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em arquitetura de soluções para aplicações de IA, dados e software.\u003c/li\u003e\u003cli\u003eConhecimento em desenvolvimento mobile, web e backend com as tecnologias listadas.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho híbrido em Blumenau.\u003c/li\u003e\u003c/ul\u003e","title":"Arquiteto de Soluções (Aplicações de IA e Dados)"},{"content":"Sobre a vagaA Hiflylabs busca uma pessoa Arquiteta de Soluções sênior para atuar em aplicações de IA e dados, em modelo híbrido, com possibilidade de atuação em Jersey City ou no Brasil.\nStack e contexto técnicoDesenvolvimento de soluções com IA generativa, LLM, RAG, LangChain, AutoGen e bancos vetoriais.Aplicações e plataformas de dados com Databricks, Databricks Apps, MLflow e Unity Catalog.Backend e APIs com Python, FastAPI, Node.js e Java.Frontend e mobile com React, Swift e Kotlin.Ambientes com Docker e práticas de CI/CD.RequisitosExperiência sênior em arquitetura de soluções para aplicações de dados, IA ou software corporativo.Conhecimento prático em integração de sistemas, APIs e desenho de soluções escaláveis.Familiaridade com ferramentas modernas de IA, pipelines de dados e entrega contínua. ","permalink":"https://kotlin.dev.br/vagas/mo5l3r02quoifv9x-hiflylabs-arquiteto-de-solucoes-aplicacoes-de-ia-e-dados/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Hiflylabs busca uma pessoa Arquiteta de Soluções sênior para atuar em aplicações de IA e dados, em modelo híbrido, com possibilidade de atuação em Jersey City ou no Brasil.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolvimento de soluções com \u003cstrong\u003eIA generativa\u003c/strong\u003e, LLM, RAG, LangChain, AutoGen e bancos vetoriais.\u003c/li\u003e\u003cli\u003eAplicações e plataformas de dados com Databricks, Databricks Apps, MLflow e Unity Catalog.\u003c/li\u003e\u003cli\u003eBackend e APIs com Python, FastAPI, Node.js e Java.\u003c/li\u003e\u003cli\u003eFrontend e mobile com React, Swift e Kotlin.\u003c/li\u003e\u003cli\u003eAmbientes com Docker e práticas de CI/CD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em arquitetura de soluções para aplicações de dados, IA ou software corporativo.\u003c/li\u003e\u003cli\u003eConhecimento prático em integração de sistemas, APIs e desenho de soluções escaláveis.\u003c/li\u003e\u003cli\u003eFamiliaridade com ferramentas modernas de IA, pipelines de dados e entrega contínua.\u003c/li\u003e\u003c/ul\u003e","title":"Arquiteto de Soluções (Aplicações de IA e Dados)"},{"content":"Sobre a vagaA CI\u0026T busca uma pessoa Arquiteta de Soluções sênior para atuação remota, com base em Campinas ou em qualquer localidade do Brasil.\nA vaga envolve desenho de soluções técnicas e decisões de arquitetura em ambientes com Kotlin, Java, mobile, cloud, mensageria, bancos de dados e observabilidade.\nResponsabilidadesDefinir arquitetura de soluções considerando requisitos funcionais, não funcionais, segurança, escalabilidade e operação.Apoiar times de engenharia em decisões técnicas, padrões de integração, APIs e evolução de plataformas.Trabalhar com ecossistemas mobile, backend, cloud, mensageria, bancos relacionais e NoSQL.Colaborar com práticas de documentação técnica, governança de arquitetura e qualidade de entrega.RequisitosExperiência sênior em arquitetura de soluções ou liderança técnica.Conhecimento em Java e Kotlin.Experiência com Android, iOS ou arquitetura para aplicações mobile.Vivência com PostgreSQL, MongoDB e Redis.Experiência com mensageria e eventos usando SNS, SQS, Kafka ou RabbitMQ.Conhecimento em Git, Git Flow e documentação de APIs com Swagger/OpenAPI.Experiência com cloud em GCP, AWS ou Azure.Vivência com Docker, Kubernetes e observabilidade com Grafana ou Datadog.DiferenciaisConhecimento em Apigee Hybrid.Experiência com Go.Conhecimento de frameworks e padrões como TOGAF.Familiaridade com práticas de segurança e ISO 27001. ","permalink":"https://kotlin.dev.br/vagas/rezvns4xizfq7zqn-ci-t-arquiteto-a-de-solucoes-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T busca uma pessoa Arquiteta de Soluções sênior para atuação remota, com base em Campinas ou em qualquer localidade do Brasil.\u003c/p\u003e\u003cp\u003eA vaga envolve desenho de soluções técnicas e decisões de arquitetura em ambientes com Kotlin, Java, mobile, cloud, mensageria, bancos de dados e observabilidade.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDefinir arquitetura de soluções considerando requisitos funcionais, não funcionais, segurança, escalabilidade e operação.\u003c/li\u003e\u003cli\u003eApoiar times de engenharia em decisões técnicas, padrões de integração, APIs e evolução de plataformas.\u003c/li\u003e\u003cli\u003eTrabalhar com ecossistemas mobile, backend, cloud, mensageria, bancos relacionais e NoSQL.\u003c/li\u003e\u003cli\u003eColaborar com práticas de documentação técnica, governança de arquitetura e qualidade de entrega.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em arquitetura de soluções ou liderança técnica.\u003c/li\u003e\u003cli\u003eConhecimento em Java e Kotlin.\u003c/li\u003e\u003cli\u003eExperiência com Android, iOS ou arquitetura para aplicações mobile.\u003c/li\u003e\u003cli\u003eVivência com PostgreSQL, MongoDB e Redis.\u003c/li\u003e\u003cli\u003eExperiência com mensageria e eventos usando SNS, SQS, Kafka ou RabbitMQ.\u003c/li\u003e\u003cli\u003eConhecimento em Git, Git Flow e documentação de APIs com Swagger/OpenAPI.\u003c/li\u003e\u003cli\u003eExperiência com cloud em GCP, AWS ou Azure.\u003c/li\u003e\u003cli\u003eVivência com Docker, Kubernetes e observabilidade com Grafana ou Datadog.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eConhecimento em Apigee Hybrid.\u003c/li\u003e\u003cli\u003eExperiência com Go.\u003c/li\u003e\u003cli\u003eConhecimento de frameworks e padrões como TOGAF.\u003c/li\u003e\u003cli\u003eFamiliaridade com práticas de segurança e ISO 27001.\u003c/li\u003e\u003c/ul\u003e","title":"Arquiteto(a) de Soluções Sênior"},{"content":"Sobre a vagaA GFT busca pessoa Desenvolvedora Android Pleno/Sênior para atuar remotamente em projetos mobile com Kotlin e Android.\nRequisitosExperiência em desenvolvimento Android com Kotlin.Conhecimento em Jetpack Compose, MVVM e Clean Architecture.Experiência com integrações via REST e WebSocket.Conhecimento em Firebase.Uso de Git e práticas de CI/CD.Modelo de trabalhoVaga remota, com referência em Barueri, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/gmskk4hfzmbk5m33-gft-desenvolvedor-android-pleno-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA GFT busca pessoa Desenvolvedora Android Pleno/Sênior para atuar remotamente em projetos mobile com Kotlin e Android.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento Android com \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eJetpack Compose\u003c/strong\u003e, \u003cstrong\u003eMVVM\u003c/strong\u003e e \u003cstrong\u003eClean Architecture\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com integrações via \u003cstrong\u003eREST\u003c/strong\u003e e \u003cstrong\u003eWebSocket\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eFirebase\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eGit\u003c/strong\u003e e práticas de \u003cstrong\u003eCI/CD\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota, com referência em Barueri, São Paulo, Brasil.\u003c/p\u003e","title":"Desenvolvedor Android Pleno/Sênior"},{"content":"Sobre a vagaA Accenture busca Desenvolvedor(a) Backend em níveis pleno, sênior e especialista para atuação híbrida em São Paulo, Campina Grande, Belém, Recife, Brasília, Rio de Janeiro, Fortaleza ou Belo Horizonte.\nA posição envolve desenvolvimento backend com Java, Kotlin e Python, construção de APIs REST e uso de frameworks modernos para aplicações corporativas.\nResponsabilidadesDesenvolver, manter e evoluir serviços backend e APIs REST.Trabalhar com bancos de dados relacionais e NoSQL.Participar de práticas ágeis com Scrum e ferramentas como Jira ou Trello.Colaborar com pipelines de CI/CD, containers e ambientes em cloud.Apoiar integrações, mensageria, observabilidade e automação de processos quando necessário.RequisitosExperiência com Java, Kotlin ou Python.Conhecimento em Spring Boot, Django, FastAPI ou Flask.Experiência com APIs REST.Testes automatizados com JUnit, Mockito, PyTest ou ferramentas equivalentes.Conhecimento em MySQL, PostgreSQL ou MongoDB.Uso de ferramentas de build e dependências como Maven, Gradle, Pip ou Poetry.Vivência com Docker, Kubernetes, Kafka ou Event Hub.Experiência com CI/CD usando Jenkins ou GitLab CI.Conhecimento em AWS, Google Cloud ou Azure.DiferenciaisExperiência com Camunda, BPM, Camel ou Quarkus.Conhecimento em Angular.Experiência com observabilidade usando Grafana ou Datadog. ","permalink":"https://kotlin.dev.br/vagas/u5k6zeskfum2ydav-accenture-desenvolvedor-a-backend-pleno-senior-e-especialista/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Accenture busca Desenvolvedor(a) Backend em níveis pleno, sênior e especialista para atuação híbrida em São Paulo, Campina Grande, Belém, Recife, Brasília, Rio de Janeiro, Fortaleza ou Belo Horizonte.\u003c/p\u003e\u003cp\u003eA posição envolve desenvolvimento backend com Java, Kotlin e Python, construção de APIs REST e uso de frameworks modernos para aplicações corporativas.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver, manter e evoluir serviços backend e APIs REST.\u003c/li\u003e\u003cli\u003eTrabalhar com bancos de dados relacionais e NoSQL.\u003c/li\u003e\u003cli\u003eParticipar de práticas ágeis com Scrum e ferramentas como Jira ou Trello.\u003c/li\u003e\u003cli\u003eColaborar com pipelines de CI/CD, containers e ambientes em cloud.\u003c/li\u003e\u003cli\u003eApoiar integrações, mensageria, observabilidade e automação de processos quando necessário.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Java, Kotlin ou Python.\u003c/li\u003e\u003cli\u003eConhecimento em Spring Boot, Django, FastAPI ou Flask.\u003c/li\u003e\u003cli\u003eExperiência com APIs REST.\u003c/li\u003e\u003cli\u003eTestes automatizados com JUnit, Mockito, PyTest ou ferramentas equivalentes.\u003c/li\u003e\u003cli\u003eConhecimento em MySQL, PostgreSQL ou MongoDB.\u003c/li\u003e\u003cli\u003eUso de ferramentas de build e dependências como Maven, Gradle, Pip ou Poetry.\u003c/li\u003e\u003cli\u003eVivência com Docker, Kubernetes, Kafka ou Event Hub.\u003c/li\u003e\u003cli\u003eExperiência com CI/CD usando Jenkins ou GitLab CI.\u003c/li\u003e\u003cli\u003eConhecimento em AWS, Google Cloud ou Azure.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Camunda, BPM, Camel ou Quarkus.\u003c/li\u003e\u003cli\u003eConhecimento em Angular.\u003c/li\u003e\u003cli\u003eExperiência com observabilidade usando Grafana ou Datadog.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Backend Pleno, Sênior e Especialista"},{"content":"Sobre a vagaA Accenture busca Desenvolvedor(a) Mobile em níveis pleno, sênior e especialista para atuação híbrida em São Paulo, Campina Grande, Fortaleza, Recife ou Belém.\nRequisitos e tecnologiasExperiência com desenvolvimento mobile usando Kotlin e Swift.Conhecimento em MVVM, Clean Architecture e integração com APIs REST.Vivência com publicação de aplicativos na Google Play e na App Store.Experiência com testes usando JUnit, Espresso e XCTest.Uso de Git, práticas de CI/CD e trabalho em times ágeis com Scrum e Jira.DiferenciaisConhecimento em Flutter.Experiência com padrões de gerenciamento de estado como Bloc, Provider e Redux. ","permalink":"https://kotlin.dev.br/vagas/da0b7i2k4a4mk5zb-accenture-desenvolvedor-a-mobile-pleno-senior-e-especialista/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Accenture busca Desenvolvedor(a) Mobile em níveis pleno, sênior e especialista para atuação híbrida em São Paulo, Campina Grande, Fortaleza, Recife ou Belém.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com desenvolvimento mobile usando \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eSwift\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eMVVM\u003c/strong\u003e, \u003cstrong\u003eClean Architecture\u003c/strong\u003e e integração com APIs \u003cstrong\u003eREST\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com publicação de aplicativos na \u003cstrong\u003eGoogle Play\u003c/strong\u003e e na \u003cstrong\u003eApp Store\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com testes usando \u003cstrong\u003eJUnit\u003c/strong\u003e, \u003cstrong\u003eEspresso\u003c/strong\u003e e \u003cstrong\u003eXCTest\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eGit\u003c/strong\u003e, práticas de \u003cstrong\u003eCI/CD\u003c/strong\u003e e trabalho em times ágeis com \u003cstrong\u003eScrum\u003c/strong\u003e e \u003cstrong\u003eJira\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eFlutter\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com padrões de gerenciamento de estado como \u003cstrong\u003eBloc\u003c/strong\u003e, \u003cstrong\u003eProvider\u003c/strong\u003e e \u003cstrong\u003eRedux\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Mobile Pleno, Sênior e Especialista"},{"content":"Sobre a vagaA Tractian busca uma pessoa Engenheira de QA de Software Pleno para atuação remota no Brasil, com possibilidade de vínculo em São Paulo.\nResponsabilidadesPlanejar, implementar e manter automação de testes para aplicações web, mobile e APIs.Integrar testes automatizados ao fluxo de desenvolvimento e pipelines de CI/CD.Apoiar a qualidade do produto com testes funcionais, regressivos e de contrato.RequisitosExperiência com automação de testes usando ferramentas como Cypress, Playwright, Selenium, Rest Assured ou Robot Framework.Conhecimento em testes mobile com Maestro, Appium, Espresso ou XCUITest.Familiaridade com TypeScript, JavaScript, Kotlin ou Swift.Experiência com GitHub Actions, GitLab CI ou Jenkins.Conhecimento em testes de contrato com Pact. ","permalink":"https://kotlin.dev.br/vagas/wy9sit9nvxpmyld9-tractian-engenheiro-de-qa-de-software-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Tractian busca uma pessoa Engenheira de QA de Software Pleno para atuação remota no Brasil, com possibilidade de vínculo em São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003ePlanejar, implementar e manter automação de testes para aplicações web, mobile e APIs.\u003c/li\u003e\u003cli\u003eIntegrar testes automatizados ao fluxo de desenvolvimento e pipelines de CI/CD.\u003c/li\u003e\u003cli\u003eApoiar a qualidade do produto com testes funcionais, regressivos e de contrato.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com automação de testes usando ferramentas como Cypress, Playwright, Selenium, Rest Assured ou Robot Framework.\u003c/li\u003e\u003cli\u003eConhecimento em testes mobile com Maestro, Appium, Espresso ou XCUITest.\u003c/li\u003e\u003cli\u003eFamiliaridade com TypeScript, JavaScript, Kotlin ou Swift.\u003c/li\u003e\u003cli\u003eExperiência com GitHub Actions, GitLab CI ou Jenkins.\u003c/li\u003e\u003cli\u003eConhecimento em testes de contrato com Pact.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de QA de Software Pleno"},{"content":"Sobre a vagaO Mercado Livre busca uma pessoa Engenheira de Software Android Sênior para atuar com Smart POS em modelo híbrido, com localização informada como Osasco ou Brasil.\nRequisitosExperiência sênior em engenharia de software.Experiência com desenvolvimento Android.Conhecimento em Kotlin.Vivência ou interesse em soluções de Smart POS e EMV.Experiência com bibliotecas compartilhadas.Informações da vagaEmpresa: Mercado LivreSenioridade: SêniorModelo de trabalho: HíbridoLocalização: Osasco ou Brasil ","permalink":"https://kotlin.dev.br/vagas/w8lo7gz60s5ydwb8-mercado-libre-engenheiro-a-de-software-android-senior-smart-pos/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO Mercado Livre busca uma pessoa Engenheira de Software Android Sênior para atuar com Smart POS em modelo híbrido, com localização informada como Osasco ou Brasil.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software.\u003c/li\u003e\u003cli\u003eExperiência com desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin.\u003c/li\u003e\u003cli\u003eVivência ou interesse em soluções de Smart POS e EMV.\u003c/li\u003e\u003cli\u003eExperiência com bibliotecas compartilhadas.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eInformações da vaga\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eEmpresa:\u003c/strong\u003e Mercado Livre\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eSenioridade:\u003c/strong\u003e Sênior\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eModelo de trabalho:\u003c/strong\u003e Híbrido\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eLocalização:\u003c/strong\u003e Osasco ou Brasil\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Android Sênior - Smart POS"},{"content":"Sobre a vagaO iFood busca uma pessoa Engenheira de Software Backend Sênior para atuar em Delivery Intelligence, com foco em sistemas backend e plataforma.\nRequisitos e tecnologiasExperiência sênior em desenvolvimento Backend.Conhecimento em Kotlin e Java.Experiência com mensageria e eventos usando Kafka, SQS e SNS.Vivência com AWS, Kubernetes, Docker e Linux.Conhecimento em Infrastructure as Code.Rust é uma tecnologia mencionada no stack da vaga.Local de trabalhoVaga presencial, com localização informada como Osasco ou Brasil.\n","permalink":"https://kotlin.dev.br/vagas/uma22x2a8g55q1mt-ifood-engenheiro-a-de-software-backend-senior-delivery-intellig/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa Engenheira de Software Backend Sênior para atuar em Delivery Intelligence, com foco em sistemas backend e plataforma.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Backend.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eJava\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com mensageria e eventos usando \u003cstrong\u003eKafka\u003c/strong\u003e, \u003cstrong\u003eSQS\u003c/strong\u003e e \u003cstrong\u003eSNS\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com \u003cstrong\u003eAWS\u003c/strong\u003e, \u003cstrong\u003eKubernetes\u003c/strong\u003e, \u003cstrong\u003eDocker\u003c/strong\u003e e Linux.\u003c/li\u003e\u003cli\u003eConhecimento em Infrastructure as Code.\u003c/li\u003e\u003cli\u003eRust é uma tecnologia mencionada no stack da vaga.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial, com localização informada como Osasco ou Brasil.\u003c/p\u003e","title":"Engenheiro(a) de Software Backend Sênior - Delivery Intelligence"},{"content":"Desde a entrada em vigor da Lei Geral de Proteção de Dados (Lei nº 13.709/2018), todo app publicado no Brasil que coleta dados de usuários precisa cumprir regras claras sobre finalidade, consentimento, transparência e segurança. Para quem desenvolve em Kotlin no Android, isso não é apenas uma obrigação jurídica — é também uma forma de construir confiança com o usuário e evitar sanções da Autoridade Nacional de Proteção de Dados (ANPD).\nEste guia prático mostra como traduzir os princípios da LGPD em decisões concretas de código: onde armazenar dados sensíveis, como pedir consentimento, como autenticar o usuário com biometria e como se preparar para mudanças que já estão em curso no ecossistema Android em 2026, como o Privacy Sandbox.\nSe você ainda está montando a base técnica, vale revisar antes nosso artigo sobre segurança de dados locais no Android com Kotlin, o guia de permissões no Android com Kotlin e a comparação Room vs SQLDelight, porque a LGPD começa exatamente na decisão de onde e como guardar cada dado.\nO que a LGPD pede para o desenvolvedor A lei se baseia em dez princípios (Art. 6º), mas, na prática do dia a dia do desenvolvimento mobile, quatro exigem atenção direta no código:\nFinalidade: colete apenas o dado que o app realmente usa. Nada de \u0026ldquo;guardar para ver se serve depois\u0026rdquo;. Transparência: o usuário precisa entender o que é coletado e por quê, em linguagem clara. Segurança: dados pessoais exigem proteção técnica contra acessos indevidos. Não discriminação: não use dados para finalidades que discriminem o usuário. O titular dos dados (seu usuário) tem direitos específicos: acesso, correção, anonimização e portabilidade. O seu app precisa conseguir apagar dados quando solicitado, e isso afeta diretamente como você modela persistência local e sincronização com backend.\nConsentimento: a base legal mais comum Para a maioria dos apps, o consentimento é a base legal mais simples. Em Kotlin, isso significa implementar um fluxo claro que (1) explica o que será coletado, (2) registra se o usuário aceitou e (3) permite revogar a decisão depois.\nUm padrão seguro é armazenar o consentimento com versão e timestamp:\ndata class Consentimento( val versaoDoTermo: String, val aceito: Boolean, val timestamp: Long, val finalidades: List\u0026lt;String\u0026gt; ) class ConsentimentoRepository(private val dataStore: DataStore\u0026lt;Preferences\u0026gt;) { private val CONSENTIMENTO = booleanPreferencesKey(\u0026#34;consentimento_aceito\u0026#34;) private val VERSAO = stringPreferencesKey(\u0026#34;consentimento_versao\u0026#34;) suspend fun registrar(decisao: Consentimento) { dataStore.edit { prefs -\u0026gt; prefs[CONSENTIMENTO] = decisao.aceito prefs[VERSAO] = decisao.versaoDoTermo } } val estado: Flow\u0026lt;Boolean\u0026gt; = dataStore.data.map { it[CONSENTIMENTO] ?: false } } Importante: o consentimento precisa ser livre, informado e inequívoco. Não basta um checkbox pré-marcado. Sempre que você mudar as finalidades de coleta, bump da versão do termo e peça consentimento de novo.\nArmazenamento seguro com EncryptedSharedPreferences e DataStore A ANPD tem cobrado cada vez mais proteção técnica, não só política. Dados pessoais no dispositivo devem ficar criptografados, especialmente em dispositivos com root ou em casos de roubo.\nPara preferências pequenas (tokens, flags sensíveis), use EncryptedSharedPreferences:\nval masterKey = MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() val prefs = EncryptedSharedPreferences.create( context, \u0026#34;dados_pessoais\u0026#34;, masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ) Para volumes maiores de dados estruturados, a recomendação moderna é combinar Room com a extensão de criptografia via SQLCipher ou usar Jetpack Security. Revisitamos essas opções em detalhe no artigo sobre segurança de dados locais.\nEvite guardar dados pessoais em SharedPreferences comum, arquivos texto ou logs. Logs em produção, inclusive, são um dos vetores mais comuns de vazamento detectado em pentests de apps brasileiros.\nAutenticação biométrica com Biometric Quando o app lida com dados sensíveis (financeiros, de saúde, documentos), a LGPD e o bom senso pedem autenticação forte antes de exibi-los. A biblioteca AndroidX Biometric resolve isso com poucas linhas:\nval promptInfo = BiometricPrompt.PromptInfo.Builder() .setTitle(\u0026#34;Desbloquear dados pessoais\u0026#34;) .setSubtitle(\u0026#34;Use biometria para acessar\u0026#34;) .setNegativeButtonText(\u0026#34;Cancelar\u0026#34;) .build() val prompt = BiometricPrompt(activity, executor, object : BiometricPrompt.AuthenticationCallback() { override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { carregarDadosSensiveis() } }) prompt.authenticate(promptInfo) Para quem já usa passkeys e Credential Manager — abordagem que detalhamos em passkeys no Android com Kotlin — vale combinar as duas camadas: biometria libera o cofre local e passkeys autenticam no backend.\nDireito ao esquecimento e portabilidade Dois direitos do titular viram requisitos funcionais: apagar dados e exportar dados. Modele isso desde o início:\ninterface DadosPessoaisService { suspend fun exportar(userId: String): DadosExportados suspend fun anonimizar(userId: String) suspend fun apagar(userId: String) } A diferença entre anonimizar e apagar importa: registros completamente anônimos podem ser mantidos para estatística, mas dados que permitam reidentificação precisam sumir de verdade, inclusive em backups com prazo definido.\nPrivacy Sandbox e a transição dos identificadores Em 2026, o Android continua avançando o Privacy Sandbox, que substitui o AD_ID por APIs que limitam rastreamento cross-app. Para apps que dependem de publicidade, isso muda a forma de coletar métricas. O ponto de atenção para a LGPD: menos rastreamento não significa dispensa de consentimento — qualquer dado pessoal, mesmo pseudonimizado, ainda se enquadra na lei.\nChecklist prático para auditoria de conformidade Antes de publicar uma nova versão, confira:\nToda coleta nova tem finalidade documentada e consentimento versionado. Dados pessoais locais estão criptografados (EncryptedSharedPreferences ou Room + SQLCipher). Existe fluxo de exclusão de conta funcional, testado de ponta a ponta. Logs de produção não expõem CPF, e-mail, localização ou tokens. Permissões do Android pedem apenas o necessário no momento de uso (revise nosso guia de permissões). A política de privacidade reflete exatamente o que o código faz — não mais, não menos. Conclusão Cumprir a LGPD em um app Android escrito em Kotlin é, sobretudo, uma questão de arquitetura: preferir armazenamento criptografado, modelar consentimento como dado de primeira classe e tratar exclusão e portabilidade como recursos, não como correções tardias. As APIs do ecossistema Jetpack — Biometric, Security, DataStore, Credential Manager — já cobrem a maior parte do caminho técnico.\nPara aprofundar o lado de backend, vale cruzar este guia com nosso artigo sobre segurança de dados locais no Android e, se você mantém infra multiplataforma, com a comparação de Kotlin Multiplatform vs Flutter, onde discutimos também como compartilhar a camada de segurança entre Android e iOS. Em projetos maiores, isso conversa diretamente com a modularização no Android com Compose, separando o módulo de privacidade do resto do app.\nPara um panorama mais amplo do ecossistema Kotlin neste ano, confira também as tendências Kotlin em 2026 no nosso portal. Quem trabalha com carteiras digitais pode achar útil ainda a leitura sobre cartão de crédito do nosso portfolio, que cobre como o mercado brasileiro trata consentimento financeiro — uma referência útil quando o seu app lida com pagamentos.\n","permalink":"https://kotlin.dev.br/blog/lgpd-android-kotlin-2026/","summary":"\u003cp\u003eDesde a entrada em vigor da \u003cstrong\u003eLei Geral de Proteção de Dados (Lei nº 13.709/2018)\u003c/strong\u003e, todo app publicado no Brasil que coleta dados de usuários precisa cumprir regras claras sobre finalidade, consentimento, transparência e segurança. Para quem desenvolve em \u003cstrong\u003eKotlin no Android\u003c/strong\u003e, isso não é apenas uma obrigação jurídica — é também uma forma de construir confiança com o usuário e evitar sanções da \u003cstrong\u003eAutoridade Nacional de Proteção de Dados (ANPD)\u003c/strong\u003e.\u003c/p\u003e","title":"LGPD no Android com Kotlin: Guia Prático para Apps em 2026 | Kotlin Brasil"},{"content":"A Splash Screen API chegou para padronizar uma das partes mais inconsistentes do Android histórico: a primeira tela do app. Durante anos, todo projeto resolvia o \u0026ldquo;tempo de inicialização\u0026rdquo; de um jeito diferente — uma Activity em branco com um logo, um Handler.postDelayed, às vezes uma biblioteca third-party — e o resultado era duplicação de cold start, animações truncadas e UX inconsistente entre fabricantes. A partir do Android 12 a plataforma passou a controlar o splash nativamente, e em 2026, com o Android 16 consolidando o SplashScreen da AndroidX Core como padrão, manter um splash legado virou dívida técnica com custo real.\nNeste guia você implementa a Splash Screen API no Android 16 com Kotlin e Jetpack Compose, do zero à migração de um projeto existente, cobrindo duration, ícone adaptativo, windowBackground, animação de saída e testes. Se você está começando um app novo, vale revisar antes o tutorial de criação do primeiro app Android e o guia de Jetpack Compose, porque a integração do splash depende da configuração de tema e da raiz de navegação em Compose.\n1. Por que não fazer um splash \u0026ldquo;na mão\u0026rdquo; A tentação de criar uma SplashActivity dedicada ainda existe, mas o custo é alto e quase sempre invisível até virar bug:\nCold start duplicado: a Activity extra inflaciona layout, cria Application-level DI, roda setContent e só então navega para a tela real. O usuário espera o custo de duas telas para ver uma. Quebra em modo gelado / AOT: em primeiro launch após instalar ou atualizar, o Android já mostra o splash do sistema por cima do seu splash manual, gerando dois logotipos piscando. Comportamento inconsistente entre OEMs: Samsung, Xiaomi e Pixel renderizam windowBackground de formas diferentes; a Splash Screen API normaliza isso. Animação de saída não suportada: o splash manual não tem hook de \u0026ldquo;deixe a plataforma animar a transição para o seu primeiro frame Compose\u0026rdquo;. Acessibilidade: a API nativa respeita contraste, dimensão mínima do ícone e tempo máximo de exibição, coisas fáceis de errar numa implementação caseira. A regra em 2026 é simples: deixe a plataforma desenhar o splash, use a AndroidX só para customizar.\n2. Dependências No libs.versions.toml (padrão que vale seguir — veja o guia de Gradle Version Catalog):\n[versions] androidxCoreSplashscreen = \u0026#34;1.0.1\u0026#34; [libraries] androidx-core-splashscreen = { group = \u0026#34;androidx.core\u0026#34;, name = \u0026#34;core-splashscreen\u0026#34;, version.ref = \u0026#34;androidxCoreSplashscreen\u0026#34; } No app/build.gradle.kts:\ndependencies { implementation(libs.androidx.core.splashscreen) } A versão 1.0.1 é estável em 2026 e cobre API 21+ com backport do comportamento do Android 12. Em API 31+ o sistema desenha nativamente; em API mais baixa, a AndroidX simula o mesmo contrato a partir do tema.\n3. O tema Theme.SplashScreen O ponto central é um tema dedicado que herda de Theme.SplashScreen. Em res/values/themes.xml:\n\u0026lt;style name=\u0026#34;Theme.App.Starting\u0026#34; parent=\u0026#34;Theme.SplashScreen\u0026#34;\u0026gt; \u0026lt;item name=\u0026#34;windowSplashScreenBackground\u0026#34;\u0026gt;@color/splash_background\u0026lt;/item\u0026gt; \u0026lt;item name=\u0026#34;windowSplashScreenAnimatedIcon\u0026#34;\u0026gt;@drawable/splash_icon\u0026lt;/item\u0026gt; \u0026lt;item name=\u0026#34;windowSplashScreenAnimationDuration\u0026#34;\u0026gt;200\u0026lt;/item\u0026gt; \u0026lt;item name=\u0026#34;postSplashScreenTheme\u0026#34;\u0026gt;@style/Theme.App\u0026lt;/item\u0026gt; \u0026lt;/style\u0026gt; Pontos críticos que erram em revisão de código:\npostSplashScreenTheme é obrigatório. Sem ele o app inteiro herda o tema de splash, quebrando Cores, ColorScheme do Compose Material 3 e tokens de windowBackground. windowSplashScreenAnimatedIcon aceita drawable vetorial ou adaptative icon. Ícones raster estouram em telas high-DPI e não animam. A duração máxima útil é ~1000ms. Acima disso o sistema corta e o app parece travado. Para uma discussão mais ampla de performance de inicialização, o guia de performance em Kotlin cobre reduzir tempo de cold start além do splash. O ícone tem área de mascaramento. Use um vector drawable com 108dp onde o conteúdo visível fica num círculo de ~72dp centralizado; o sistema pode recortar as bordas. No AndroidManifest.xml:\n\u0026lt;application android:name=\u0026#34;.App\u0026#34; android:theme=\u0026#34;@style/Theme.App.Starting\u0026#34;\u0026gt; \u0026lt;activity android:name=\u0026#34;.MainActivity\u0026#34; android:exported=\u0026#34;true\u0026#34; android:theme=\u0026#34;@style/Theme.App.Starting\u0026#34;\u0026gt; \u0026lt;intent-filter\u0026gt; \u0026lt;action android:name=\u0026#34;android.intent.action.MAIN\u0026#34; /\u0026gt; \u0026lt;category android:name=\u0026#34;android.intent.category.LAUNCHER\u0026#34; /\u0026gt; \u0026lt;/intent-filter\u0026gt; \u0026lt;/activity\u0026gt; \u0026lt;/application\u0026gt; 4. Instalar o splash na Activity A chamada precisa acontecer antes de super.onCreate e antes de setContent. É a parte mais fácil de errar:\nclass MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { val splash = installSplashScreen() super.onCreate(savedInstanceState) var contentReady = mutableStateOf(false) splash.setKeepOnScreenCondition { !contentReady.value } enableEdgeToEdge() setContent { AppRoot(contentReady = contentReady) } } } O setKeepOnScreenCondition é o substituto moderno do \u0026ldquo;segure o splash enquanto carrega dados\u0026rdquo;. Enquanto retornar true, o sistema mantém o splash visível; ao virar false, ele anima a saída e entrega o primeiro frame Compose. Esse padrão combina bem com edge-to-edge no Android 16, que agora é default.\nImportante: não bloqueie a main thread dentro de setKeepOnScreenCondition. O callback roda no frame loop; carregamento real deve rodar em LaunchedEffect, viewModelScope ou Application.onCreate. Se você precisa inicializar DI, logging ou analytics antes da UI, mova para Application ou use um Startup Provider da AndroidX.\n5. Animação de saída customizada O splash padrão já faz fade-out, mas você pode adicionar uma animação de saída mais marcada com setOnExitAnimationListener:\nsplash.setOnExitAnimationListener { splashView -\u0026gt; val iconView = splashView.iconView ?: run { splashView.remove() return@setOnExitAnimationListener } val scale = ObjectAnimator.ofFloat( iconView, View.SCALE_X, 1f, 0.6f ).apply { duration = 150 } val alpha = ObjectAnimator.ofFloat( splashView.view, View.ALPHA, 1f, 0f ).apply { duration = 150 } AnimatorSet().apply { playTogether(scale, alpha) doOnEnd { splashView.remove() } start() } } Duas armadilhas:\nSempre chame splashView.remove() no fim. Esquecer isso segura o splash para sempre e vira ANR em produção. Não exceda ~300ms de animação de saída. O usuário já esperou o cold start; alongar a transição causa sensação de lentidão. 6. Splash no Android 16 especificamente O Android 16 reforça duas coisas que vale revisar em apps em produção:\nenableEdgeToEdge() é default, então o tema Theme.App.Starting precisa considerar windowLayoutInDisplayCutoutMode e statusBarColor transparentes, senão o splash mostra borda colorida que some abruptamente na UI real. Modo gelado pré-aquecido: o sistema pode mostrar o splash antes mesmo do processo do app subir, com o ícone em silhueta. Use um ícone com contraste forte contra windowSplashScreenBackground para evitar um \u0026ldquo;fantasma\u0026rdquo; ilegível. Suporte a tela inicial preenchida em tablets/dobráveis: o splash centraliza o ícone em qualquer tamanho de tela; layouts manuais costumam quebrar em res/values-sw600dp. Para apps que ainda têm windowBackground customizado, remova-o do tema base e migre para Theme.SplashScreen herdando o comportamento de fundo — isso evita flashes de cor diferente entre splash e UI.\n7. Migração do splash legado O caminho padrão para um app que ainda usa SplashActivity:\nRemova a Activity legada e o filtro de LAUNCHER dela. Torne a MainActivity real a exportada com MAIN/LAUNCHER. Aplique Theme.App.Starting na MainActivity e no \u0026lt;application\u0026gt;. Chame installSplashScreen() antes de super.onCreate. Mova qualquer Handler.postDelayed / Thread.sleep para setKeepOnScreenCondition controlado por estado real (carregamento de feature flags, sessão, etc.). Apague layouts, drawables e bibliotecas de splash third-party. Rode o app em API 21, 31 e o emulador Android 16 para validar consistência. Esse fluxo costuma reduzir o cold start percebido em 150–300ms e elimina uma classe inteira de bugs de OEM. Se você mantém Feature Flags no projeto, vale gatear a migração por flag para poder reverter rápido em caso de regressão visual.\n8. Como medir o tempo de splash O tempo percebido de splash não é o que você acha — é o que o usuário vê. Para medir corretamente:\nUse adb shell am start -W com.seu.app/.MainActivity e observe WaitTime e TotalTime. Em instrumentação, capture ActivityManager.ProcessState ao redor do primeiro frame Compose; o delta entre installSplashScreen() e o primeiro frame estável é o tempo real de splash. Em produção, registre um evento app_first_frame com duração desde Application.onCreate; agregue por versão de Android e modelo de dispositivo. Não confie em cronômetro na mão. Dispositivos com thermal throttle, primeiro launch após OTA ou apps pesados em DI mostram tempos bem diferentes do dev machine.\n9. Erros comuns em revisão de código Esquecer postSplashScreenTheme e quebrar o tema do app inteiro. Chamar installSplashScreen() depois de setContent — vira no-op silencioso. Manter windowDisablePreview no tema, que desativa o splash do sistema. Usar windowSplashScreenAnimatedIcon com bitmap grande em vez de vector — estoura DPI e consome memória no cold start. Animar saída sem chamar splashView.remove(). Pedir permissão de rede ou I/O dentro do callback setKeepOnScreenCondition. 10. Quando NÃO usar splash A Splash Screen API é para tempo de inicialização frio inevitável, não para \u0026ldquo;dar uma sensação de carregamento\u0026rdquo;. Se o seu app abre em menos de 300ms e você está segurando o splash artificialmente, está piorando a UX — remova-o e deixe a plataforma mostrar o mínimo necessário. Para carregamento de dados pesado, prefira skeleton screens na própria UI Compose; o tutorial de Jetpack Compose cobre estados de loading com Crossfade e AnimatedContent.\nConclusão A Splash Screen API no Android 16 é o caminho correto para qualquer app Kotlin em 2026: padroniza o cold start, respeita OEMs, suporta animação de saída e se integra limpo com Compose e edge-to-edge. A migração de um splash legado é pequena (um tema, uma linha em onCreate, um callback de condição), mas remove uma fonte permanente de bugs visuais e reduz o tempo percebido de inicialização. A regra é deixar a plataforma desenhar o splash e só customizar o que agrega UX real — ícone da marca, cor de fundo, animação de saída curta. Para o resto, gaste energia em baixar o cold start de verdade, que é onde a melhoria de UX acontece.\n","permalink":"https://kotlin.dev.br/blog/splash-screen-android-16-kotlin-2026/","summary":"\u003cp\u003eA Splash Screen API chegou para padronizar uma das partes mais inconsistentes do Android histórico: a primeira tela do app. Durante anos, todo projeto resolvia o \u0026ldquo;tempo de inicialização\u0026rdquo; de um jeito diferente — uma \u003ccode\u003eActivity\u003c/code\u003e em branco com um logo, um \u003ccode\u003eHandler.postDelayed\u003c/code\u003e, às vezes uma biblioteca third-party — e o resultado era duplicação de cold start, animações truncadas e UX inconsistente entre fabricantes. A partir do Android 12 a plataforma passou a controlar o splash nativamente, e em 2026, com o \u003cstrong\u003eAndroid 16\u003c/strong\u003e consolidando o \u003ccode\u003eSplashScreen\u003c/code\u003e da AndroidX Core como padrão, manter um splash legado virou dívida técnica com custo real.\u003c/p\u003e","title":"Splash Screen API no Android 16 com Kotlin e Jetpack Compose | Kotlin Brasil"},{"content":"O Material Design sempre foi uma linguagem visual competente, mas durante anos carregou uma crítica justa entre times de produto Android: ele era \u0026ldquo;plano demais\u0026rdquo;, geométrico e, em muitos apps, indistinguível. O Google respondeu a isso com o Material 3 Expressive, uma evolução lançada em meados de 2025 que amplifica expressividade visual sem quebrar o contrato do Material 3 que já tínhamos em produção. Em 2026, com a androidx.compose.material3 madura e o Android 16, adotar o Expressive deixou de ser experimento e virou a configuração padrão recomendada para apps novos.\nNeste guia você implementa o Material 3 Expressive com Jetpack Compose e Kotlin em 2026, do zero à migração de um tema existente, cobrindo as novas formas (Shape), tipografia expressiva, fonte variável, motion com Spring e SharedTransition, layouts adaptativos por WindowSizeClass e testes visuais. Se você ainda não dominou o Compose, vale revisar antes o guia de Jetpack Compose e o artigo sobre edge-to-edge no Android 16, porque o Expressive pressupõe uma base sólida de theming e janela.\n1. O que muda do Material 3 para o Material 3 Expressive O Expressive não é o Material 4. É uma expansão do mesmo material3 que você já usa, ativada por API e por tokens de tema. As mudanças centrais são:\nShapes mais vivos: além do Shapes clássico (extra-small a large), o Expressive introduz o LargeShapes, MediumShapes e SmallShapes com cantos malhosos (RoundedCornerShape, SquircleShape) e dimensões maiores, dando personalidade a cards, botões e sheets. Tipografia expressiva: tipografia com tamanhos e pesos mais contrastantes, pensada para display. Em vez de só headlineLarge, o tema expõe um Typography com variações ópticas e suporte de primeira classe a fonte variável (variable font), permitindo FontVariation.Settings por token. Motion como fundação: animações baseadas em Spring (não mais só tweens lineares), SharedTransitionLayout para transições entre telas e expressiveMotionScheme() que entrega curvas consistentes. Layouts adaptativos nativos: o WindowSizeClass passa a guiar não só colunas, mas densidade, spacing e tipo de navegação (bottom bar vs. rail vs. drawer) de forma declarativa. Cores tonais mais ricas: a paleta dinâmica (dynamicColor) continua, mas o Expressive adiciona harmonias de cor e o conceito de \u0026ldquo;cor de destaque\u0026rdquo; que se adapta ao conteúdo. A boa notícia para quem já tem app em produção: a migração é incremental. Você pode ativar Expressive por componente, sem reescrever o tema inteiro.\n2. Dependências e versões No libs.versions.toml (padrão que vale seguir — veja o artigo sobre Gradle Version Catalog):\n[versions] androidxComposeBom = \u0026#34;2026.03.00\u0026#34; androidxMaterial3Expressive = \u0026#34;1.4.0\u0026#34; [libraries] androidx-compose-bom = { group = \u0026#34;androidx.compose\u0026#34;, name = \u0026#34;compose-bom\u0026#34;, version.ref = \u0026#34;androidxComposeBom\u0026#34; } androidx-material3-expressive = { group = \u0026#34;androidx.compose.material3\u0026#34;, name = \u0026#34;material3\u0026#34;, version.ref = \u0026#34;androidxMaterial3Expressive\u0026#34; } No app/build.gradle.kts:\ndependencies { implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.material3.expressive) } Em 2026 a material3 já traz o Expressive embutido — não há um artifact separado material3-expressive. O que existe é um scheme (expressiveColorScheme, expressiveMotionScheme) e componentes novos (FlexibleBottomSheet, LoadingIndicator) que você opta por usar.\n3. Esquema de cores expressivo O ponto de entrada é o MaterialExpressiveTheme, que sobrescreve o MaterialTheme clássico injetando os esquemas expressivos:\n@Composable fun KotlinBrTheme( darkTheme: Boolean = isSystemInDarkTheme(), dynamicColor: Boolean = true, content: @Composable () -\u0026gt; Unit ) { val context = LocalContext.current val baseScheme = when { dynamicColor \u0026amp;\u0026amp; Build.VERSION.SDK_INT \u0026gt;= Build.VERSION_CODES.S -\u0026gt; if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) darkTheme -\u0026gt; DarkColors else -\u0026gt; LightColors } val expressiveScheme = if (darkTheme) { expressiveDarkColorScheme(baseScheme) } else { expressiveLightColorScheme(baseScheme) } MaterialExpressiveTheme( colorScheme = expressiveScheme, typography = KotlinTypography, shapes = KotlinShapes(), motionScheme = expressiveMotionScheme(), content = content ) } O expressiveLightColorScheme deriva variações extra (tons 60, 70, 80) a partir do baseScheme, expondo cores como colorScheme.containerHighest e colorScheme.onAccentContainer. Quando dynamicColor está ativo (Android 12+), o esquema herda o papel de parede — comportamento idêntico ao Material 3 clássico, mas com mais graus de cor disponíveis.\n4. Shapes e formas expressivas A maior mudança visual fica nas formas. O Expressive introduz Shapes() com mais níveis e cantos maiores:\n@Composable fun KotlinShapes(): Shapes = Shapes( extraSmall = RoundedCornerShape(8.dp), small = RoundedCornerShape(12.dp), medium = RoundedCornerShape(20.dp), large = RoundedCornerShape(32.dp), extraLarge = RoundedCornerShape(48.dp) ) Para componentes de destaque — FAB, cards hero, bottom sheets — o Expressive oferece SquircleShape (canto \u0026ldquo;superelíptico\u0026rdquo;, o mesmo do iOS) e o MaterialShapes com formas matemáticas nomeadas (Cookie9Sided, Slanted). Use com parcimônia: formas exóticas funcionam em pontos focais, não em listas inteiras.\nFloatingActionButton( onClick = { /* ... */ }, shape = MaterialShapes.Cookie9Sided.toShape(), containerColor = MaterialTheme.colorScheme.primaryContainer, contentColor = MaterialTheme.colorScheme.onPrimaryContainer ) { Icon(Icons.Default.Add, contentDescription = \u0026#34;Adicionar\u0026#34;) } 5. Tipografia expressiva com fonte variável A tipografia expressiva ganha mais contraste. Um Typography típico:\nval KotlinTypography = Typography( displayLarge = TextStyle( fontFamily = VariableFont, fontWeight = FontWeight.W700, fontSize = 57.sp, lineHeight = 64.sp, letterSpacing = (-0.25).sp ), headlineLarge = TextStyle( fontFamily = VariableFont, fontWeight = FontWeight.W600, fontSize = 32.sp, lineHeight = 40.sp ), bodyLarge = TextStyle( fontFamily = VariableFont, fontWeight = FontWeight.W400, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.5.sp ) ) Para usar fonte variável, carregue via FontVariation:\nval VariableFont = FontFamily( Font( R.font.inter_variable, variationSettings = FontVariation.Settings( FontVariation.weight(600), FontVariation.slant(0f), FontVariation.opticalSize(16f) ) ) ) A vantagem é performance e consistência: um único arquivo .ttf cobre toda a faixa de peso (100–900), eliminando o bundle de múltiplas fontes e garantindo transições suaves em animações que interpolam fontWeight.\n6. Motion com Spring e SharedTransition O expressiveMotionScheme() entrega curvas pré-configuradas, mas o real ganho do Expressive está no uso direto de Spring e SharedTransitionLayout. Um exemplo de transição entre um item de lista e seu detalhe:\nSharedTransitionLayout { NavHost(navController, startDestination = \u0026#34;lista\u0026#34;) { composable(\u0026#34;lista\u0026#34;) { ListaScreen( onItemClick = { id -\u0026gt; navController.navigate(\u0026#34;detalhe/$id\u0026#34;) }, animatedVisibilityScope = this@composable, sharedTransitionScope = this@SharedTransitionLayout ) } composable(\u0026#34;detalhe/{id}\u0026#34;) { backStackEntry -\u0026gt; DetalheScreen( id = backStackEntry.arguments?.getString(\u0026#34;id\u0026#34;).orEmpty(), animatedVisibilityScope = this@composable, sharedTransitionScope = this@SharedTransitionLayout ) } } } Dentro do item compartilhado, marque-o com Modifier.sharedElement():\nImage( painter = rememberAsyncImagePainter(post.imagemUrl), contentDescription = post.titulo, modifier = Modifier .size(120.dp) .sharedElement( rememberSharedContentState(key = \u0026#34;imagem-${post.id}\u0026#34;), animatedVisibilityScope = animatedVisibilityScope ) ) O resultado é a imagem \u0026ldquo;voando\u0026rdquo; da lista para o detalhe com interpolação automática de tamanho e posição — sem biblioteca third-party, sem boilerplate de Transition.\nPara microinterações, prefira Spring a tween:\nval scale by animateFloatAsState( targetValue = if (pressed) 0.95f else 1f, animationSpec = spring( dampingRatio = Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessLow ), label = \u0026#34;scale\u0026#34; ) 7. Layouts adaptativos com WindowSizeClass O Expressive formaliza a adaptação por tamanho de janela, algo essencial em 2026 com foldables e tablets rodando Android 16. O WindowSizeClass classifica a largura em compact (\u0026lt;600dp), medium (600–840dp) e expanded (\u0026gt;840dp):\nval windowSize = currentWindowAdaptiveInfo().windowSizeClass when (windowSize.windowWidthSizeClass) { WindowWidthSizeClass.Compact -\u0026gt; { // Smartphone em retrato: bottom bar Scaffold(bottomBar = { BottomBar() }) { padding -\u0026gt; FeedCompact(contentPadding = padding) } } WindowWidthSizeClass.Medium -\u0026gt; { // Tablet pequeno / foldable aberto: rail Scaffold { FeedMedium() } } else -\u0026gt; { // Tablet grande / desktop: lista-detalhe TwoPaneLayout() } } Esse padrão também melhora a performance de scroll em telas largas e habilita corretamente o edge-to-edge no Android 16, evitando o clássico bug de conteúdo colado na barra do sistema.\n8. Componentes novos que valem a pena O Expressive trouxe componentes que resolvem dores reais:\nLoadingIndicator: substitui o CircularProgressIndicator com um spinner que \u0026ldquo;respira\u0026rdquo; e pode ganhar cor de destaque, alinhado ao motion expressivo. FlexibleBottomSheet: bottom sheet que respeita gestos e se adapta ao conteúdo sem ocupar a tela toda, ideal para contextos rápidos. SplitToggleChip: chip de filtro com área de toque separada da seleção, melhorando acessibilidade. Carousel: carrossel acessível com snap e suporte a itens de largura variável, substituindo o HorizontalPager para casos de showcase. LoadingIndicator( modifier = Modifier.padding(24.dp), color = MaterialTheme.colorScheme.primary ) 9. Migração gradual de um app existente Para um app já em Material 3 clássico, a migração pode ser feita em três passos reversíveis:\nSubstituir MaterialTheme por MaterialExpressiveTheme no nível raiz. Como ambos expõem o mesmo colorScheme e typography, os componentes existentes continuam funcionando sem alteração. Ativar expressiveMotionScheme() e trocar tweens críticos por Spring onde há feedback tátil (botões, FAB, chips). Adotar WindowSizeClass em telas-chave (lista, detalhe, configurações) antes de tocar em componentes novos. Cada passo é um commit isolado, testável e revertível. Em apps grandes, vale orquestrar isso junto com a modularização Android em Compose para que cada feature adopte Expressive no seu ritmo.\n10. Performance, acessibilidade e testes O Expressive aumenta o uso de animação e fontes variáveis, então alguns cuidados:\nHonorar \u0026ldquo;Remover animações\u0026rdquo;: o Compose expõe LocalAccessibilityManager.currentReducedMotion() (ou Settings.Global.ANIMATOR_DURATION_SCALE). Desligue Spring bouncy e SharedTransition quando o usuário solicitar movimento reduzido. Baseline profiles: animações e SharedTransition se beneficiam de AOT. Gere profiles com o Macrobenchmark para manter 60fps em dispositivos low-end. Contraste: o esquema expressivo deriva muitos tons; valide contraste WCAG AA nos textos sobre containerHighest. Glance e widgets: widgets de homescreen ainda usam o glance (veja o guia de Glance Widgets) e não herdam MaterialExpressiveTheme — use o ColorScheme do app como referência visual, mas mapeie para ColorProviders do Glance. Para testes visuais, o snapshot testing em Compose é o gate natural: capture a versão Material 3 clássica, migre e compare os diffs conscientemente.\n11. Quando NÃO adotar Expressive Expressivo é uma escolha de produto, não uma obrigação técnica. Evite quando:\nO app tem marca muito forte com design system próprio (bancos, fintechs) — o Expressive compete visualmente com sua identidade. A audiência é majoritariamente acessibilidade-first e prefere UIs sóbrias (apps governamentais, saúde) — o contraste extra pode distrair. O time não tem banda para testar animações em diversos dispositivos — motion mal calibrado vira jank em Android low-end, pior que sem animação. Conclusão O Material 3 Expressive é o primeiro \u0026ldquo;Material\u0026rdquo; que se sente vivo desde o lançamento do Material You. Com Jetpack Compose e Kotlin em 2026, ele entrega ganhos reais de percepção de qualidade, motion fluido e adaptação a foldables — sem exigir reescrita. Aplique de forma incremental, meça performance com baseline profiles, honoreie preferências de acessibilidade e você terá um app que parece de 2026, não de 2021.\nPara ir além, combine Expressive com os widgets de homescreen com Glance e uma arquitetura modular em Compose — o resultado é uma base Android moderna, performática e pronta para escalar junto com o ecossistema Kotlin.\n","permalink":"https://kotlin.dev.br/blog/material-3-expressive-compose-kotlin-2026/","summary":"\u003cp\u003eO Material Design sempre foi uma linguagem visual competente, mas durante anos carregou uma crítica justa entre times de produto Android: ele era \u0026ldquo;plano demais\u0026rdquo;, geométrico e, em muitos apps, indistinguível. O Google respondeu a isso com o \u003cstrong\u003eMaterial 3 Expressive\u003c/strong\u003e, uma evolução lançada em meados de 2025 que amplifica expressividade visual sem quebrar o contrato do Material 3 que já tínhamos em produção. Em 2026, com a \u003ccode\u003eandroidx.compose.material3\u003c/code\u003e madura e o Android 16, adotar o Expressive deixou de ser experimento e virou a configuração padrão recomendada para apps novos.\u003c/p\u003e","title":"Material 3 Expressive com Jetpack Compose e Kotlin em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaVaga para Engenheiro Principal Mobile sênior em modelo remoto.\nRequisitosExperiência em desenvolvimento mobileConhecimento em Kotlin, Kotlin Multiplatform, React Native e SwiftLocalizaçãoRemoto na Califórnia, Estados Unidos, China ou América do Sul.\n","permalink":"https://kotlin.dev.br/vagas/83dajfos5exraeoz-iherb-engenheiro-principal-mobile/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga para Engenheiro Principal Mobile sênior em modelo remoto.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento mobile\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Kotlin Multiplatform, React Native e Swift\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocalização\u003c/h3\u003e\u003cp\u003eRemoto na Califórnia, Estados Unidos, China ou América do Sul.\u003c/p\u003e","title":"Engenheiro Principal - Mobile"},{"content":"Sobre a vagaBuscamos um Engenheiro de Software Júnior para desenvolvimento de aplicações com Kotlin e Android. A vaga é presencial em Recife.\nResponsabilidadesDesenvolver aplicações Android utilizando Kotlin.Aplicar padrões de arquitetura como MVVM e Clean Architecture.Utilizar Compose para construção de interfaces.Trabalhar com Linux e scripts em Bash e Zsh.RequisitosConhecimento em Kotlin.Experiência com desenvolvimento Android.Familiaridade com MVVM, Compose e Clean Architecture.Conhecimentos em Linux, Bash e Zsh. ","permalink":"https://kotlin.dev.br/vagas/bz6w1wev3l4txa8j-cesar-engenheiro-de-software-junior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Engenheiro de Software Júnior para desenvolvimento de aplicações com Kotlin e Android. A vaga é presencial em Recife.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver aplicações Android utilizando Kotlin.\u003c/li\u003e\u003cli\u003eAplicar padrões de arquitetura como MVVM e Clean Architecture.\u003c/li\u003e\u003cli\u003eUtilizar Compose para construção de interfaces.\u003c/li\u003e\u003cli\u003eTrabalhar com Linux e scripts em Bash e Zsh.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eConhecimento em Kotlin.\u003c/li\u003e\u003cli\u003eExperiência com desenvolvimento Android.\u003c/li\u003e\u003cli\u003eFamiliaridade com MVVM, Compose e Clean Architecture.\u003c/li\u003e\u003cli\u003eConhecimentos em Linux, Bash e Zsh.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Software Júnior"},{"content":"Sobre a vagaPosição de Engenheiro de Software Pleno para atuar de forma remota no Brasil, com foco em Java, Quarkus e AWS.\nResponsabilidadesDesenvolvimento de software utilizando Java e Quarkus.Integração com serviços de mensageria como Kafka, SQS e RabbitMQ.Implementação de soluções em AWS, incluindo Lambda, API Gateway e SNS.Gerenciamento de bancos de dados MySQL e PostgreSQL.Utilização de Docker, Kubernetes e ECS para deploy e orquestração.Trabalho com infraestrutura como código usando Terraform, CloudFormation e Ansible.RequisitosExperiência intermediária em Java e Quarkus.Conhecimento em AWS e serviços relacionados.Familiaridade com Docker e Kubernetes.Experiência com mensageria e bancos de dados relacionais.Conhecimento em Python, Kotlin ou Golang é desejável. ","permalink":"https://kotlin.dev.br/vagas/vm9cvqgknvd6hvw8-exadel-engenheiro-de-software-pleno-java-quarkus-aws/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003ePosição de Engenheiro de Software Pleno para atuar de forma remota no Brasil, com foco em Java, Quarkus e AWS.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolvimento de software utilizando Java e Quarkus.\u003c/li\u003e\u003cli\u003eIntegração com serviços de mensageria como Kafka, SQS e RabbitMQ.\u003c/li\u003e\u003cli\u003eImplementação de soluções em AWS, incluindo Lambda, API Gateway e SNS.\u003c/li\u003e\u003cli\u003eGerenciamento de bancos de dados MySQL e PostgreSQL.\u003c/li\u003e\u003cli\u003eUtilização de Docker, Kubernetes e ECS para deploy e orquestração.\u003c/li\u003e\u003cli\u003eTrabalho com infraestrutura como código usando Terraform, CloudFormation e Ansible.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência intermediária em Java e Quarkus.\u003c/li\u003e\u003cli\u003eConhecimento em AWS e serviços relacionados.\u003c/li\u003e\u003cli\u003eFamiliaridade com Docker e Kubernetes.\u003c/li\u003e\u003cli\u003eExperiência com mensageria e bancos de dados relacionais.\u003c/li\u003e\u003cli\u003eConhecimento em Python, Kotlin ou Golang é desejável.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Software Pleno (Java + Quarkus + AWS)"},{"content":"Sobre a vagaEstamos contratando um Engenheiro Full Stack Sênior para a equipe de Supply Tech da CookUnity. A vaga é remota para profissionais na América do Sul.\nResponsabilidadesDesenvolvimento de aplicações full stack com Kotlin e Java.Utilização de Micronaut e Spring Boot no backend.Construção de interfaces com React e Next.js.Integração com sistemas de mensageria como Kafka, SQS e RabbitMQ.Gerenciamento de dados em PostgreSQL e MySQL.RequisitosExperiência com Kotlin, Java, Micronaut e Spring Boot.Conhecimento em React e Next.js.Familiaridade com GraphQL e mensageria como Kafka, SQS e RabbitMQ.Experiência com Docker, Kubernetes e Terraform.Conhecimento em AWS, GCP ou Azure.DiferenciaisExperiência com Temporal para fluxos de trabalho.Conhecimento em ferramentas de IA como ChatGPT e Claude. ","permalink":"https://kotlin.dev.br/vagas/2hvpop3p1gqe8icw-cookunity-engenheiro-full-stack-senior-supply-tech/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eEstamos contratando um Engenheiro Full Stack Sênior para a equipe de Supply Tech da CookUnity. A vaga é remota para profissionais na América do Sul.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolvimento de aplicações full stack com Kotlin e Java.\u003c/li\u003e\u003cli\u003eUtilização de Micronaut e Spring Boot no backend.\u003c/li\u003e\u003cli\u003eConstrução de interfaces com React e Next.js.\u003c/li\u003e\u003cli\u003eIntegração com sistemas de mensageria como Kafka, SQS e RabbitMQ.\u003c/li\u003e\u003cli\u003eGerenciamento de dados em PostgreSQL e MySQL.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin, Java, Micronaut e Spring Boot.\u003c/li\u003e\u003cli\u003eConhecimento em React e Next.js.\u003c/li\u003e\u003cli\u003eFamiliaridade com GraphQL e mensageria como Kafka, SQS e RabbitMQ.\u003c/li\u003e\u003cli\u003eExperiência com Docker, Kubernetes e Terraform.\u003c/li\u003e\u003cli\u003eConhecimento em AWS, GCP ou Azure.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Temporal para fluxos de trabalho.\u003c/li\u003e\u003cli\u003eConhecimento em ferramentas de IA como ChatGPT e Claude.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro Full Stack Sênior, Supply Tech"},{"content":"Sobre a vagaProcuramos um Líder Técnico Mobile experiente para liderar equipes de desenvolvimento Android e iOS. Você será responsável pela arquitetura, qualidade técnica e mentoria de desenvolvedores em projetos desafiadores.\nResponsabilidadesLiderar e mentorizar equipes de desenvolvimento mobileDefinir arquitetura técnica e padrões de códigoGarantir qualidade e boas práticas em projetos Android e iOSColaborar com stakeholders para alinhamento técnicoImplementar e manter pipelines de CI/CDRequisitosExperiência sênior com desenvolvimento Android (Kotlin)Experiência sênior com desenvolvimento iOS (Swift)Sólido conhecimento em arquitetura de software (Clean Architecture, MVVM)Experiência com Jetpack Compose e/ou SwiftUIConhecimento em APIs e integração de serviçosInglês avançadoExperiência em liderança técnica e mentoriaDiferenciaisExperiência com CI/CD e automação de testesConhecimento em arquitetura MultiplatformPortfólio com aplicativos em produção ","permalink":"https://kotlin.dev.br/vagas/f4qebxh6mnebkhb9-accenture-lider-tecnico-mobile-android-ios/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eProcuramos um Líder Técnico Mobile experiente para liderar equipes de desenvolvimento Android e iOS. Você será responsável pela arquitetura, qualidade técnica e mentoria de desenvolvedores em projetos desafiadores.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLiderar e mentorizar equipes de desenvolvimento mobile\u003c/li\u003e\u003cli\u003eDefinir arquitetura técnica e padrões de código\u003c/li\u003e\u003cli\u003eGarantir qualidade e boas práticas em projetos Android e iOS\u003c/li\u003e\u003cli\u003eColaborar com stakeholders para alinhamento técnico\u003c/li\u003e\u003cli\u003eImplementar e manter pipelines de CI/CD\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com desenvolvimento Android (Kotlin)\u003c/li\u003e\u003cli\u003eExperiência sênior com desenvolvimento iOS (Swift)\u003c/li\u003e\u003cli\u003eSólido conhecimento em arquitetura de software (Clean Architecture, MVVM)\u003c/li\u003e\u003cli\u003eExperiência com Jetpack Compose e/ou SwiftUI\u003c/li\u003e\u003cli\u003eConhecimento em APIs e integração de serviços\u003c/li\u003e\u003cli\u003eInglês avançado\u003c/li\u003e\u003cli\u003eExperiência em liderança técnica e mentoria\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com CI/CD e automação de testes\u003c/li\u003e\u003cli\u003eConhecimento em arquitetura Multiplatform\u003c/li\u003e\u003cli\u003ePortfólio com aplicativos em produção\u003c/li\u003e\u003c/ul\u003e","title":"Líder Técnico Mobile Android/iOS"},{"content":"Sobre a vagaProcuramos um Middle Software Engineer para integrar nosso time de desenvolvimento. Você trabalhará com Java, Kotlin e tecnologias modernas de cloud computing, contribuindo para sistemas escaláveis e de alta performance.\nResponsabilidadesDesenvolver e manter aplicações em Java e KotlinTrabalhar com arquitetura de microsserviços e sistemas distribuídosImplementar soluções com Kafka, RabbitMQ e SQS para processamento de mensagensGerenciar infraestrutura em nuvem usando AWS (Lambda, ECS, API Gateway, SNS)Colaborar com o time em code reviews e melhoria contínuaRequisitosExperiência sólida com Java e/ou KotlinConhecimento em arquitetura de microsserviços e sistemas distribuídosExperiência com ferramentas de orquestração (Kubernetes, Docker)Familiaridade com serviços AWS (Lambda, ECS, API Gateway)Conhecimento em bancos de dados relacionais (MySQL, PostgreSQL)Experiência com infraestrutura como código (Terraform, CloudFormation, Ansible)DiferenciaisExperiência com Go ou PythonConhecimento em CI/CD e DevOpsContribuições em projetos open source ","permalink":"https://kotlin.dev.br/vagas/c8iu6r9x0ktd1m9c-exadel-middle-software-engineer-java/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eProcuramos um Middle Software Engineer para integrar nosso time de desenvolvimento. Você trabalhará com Java, Kotlin e tecnologias modernas de cloud computing, contribuindo para sistemas escaláveis e de alta performance.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações em Java e Kotlin\u003c/li\u003e\u003cli\u003eTrabalhar com arquitetura de microsserviços e sistemas distribuídos\u003c/li\u003e\u003cli\u003eImplementar soluções com Kafka, RabbitMQ e SQS para processamento de mensagens\u003c/li\u003e\u003cli\u003eGerenciar infraestrutura em nuvem usando AWS (Lambda, ECS, API Gateway, SNS)\u003c/li\u003e\u003cli\u003eColaborar com o time em code reviews e melhoria contínua\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sólida com Java e/ou Kotlin\u003c/li\u003e\u003cli\u003eConhecimento em arquitetura de microsserviços e sistemas distribuídos\u003c/li\u003e\u003cli\u003eExperiência com ferramentas de orquestração (Kubernetes, Docker)\u003c/li\u003e\u003cli\u003eFamiliaridade com serviços AWS (Lambda, ECS, API Gateway)\u003c/li\u003e\u003cli\u003eConhecimento em bancos de dados relacionais (MySQL, PostgreSQL)\u003c/li\u003e\u003cli\u003eExperiência com infraestrutura como código (Terraform, CloudFormation, Ansible)\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Go ou Python\u003c/li\u003e\u003cli\u003eConhecimento em CI/CD e DevOps\u003c/li\u003e\u003cli\u003eContribuições em projetos open source\u003c/li\u003e\u003c/ul\u003e","title":"Middle Software Engineer (Java)"},{"content":"Sobre a vagaA Amazon está procurando um Desenvolvedor de Software Mid Level para integrar a equipe IES Latech Latam em Belo Horizonte. Você será responsável pelo desenvolvimento e manutenção de sistemas robustos utilizando as melhores práticas de engenharia de software.\nResponsabilidadesDesenvolver e manter aplicações de software usando Kotlin, Java e outras linguagens modernasTrabalhar com arquiteturas de microsserviços e Web ServicesColaborar com equipes multidisciplinares em um ambiente AgileImplementar soluções na plataforma AWSParticipar de code reviews e melhorias contínuasRequisitosExperiência sólida em desenvolvimento com Kotlin e/ou JavaConhecimento de Linux/UNIX e ferramentas de desenvolvimentoFamiliaridade com metodologias ágeis (SCRUM, Kanban)Experiência com Web Services e APIs RESTfulConhecimento de AWS ou outras plataformas de cloudDiferenciaisExperiência com múltiplas linguagens (C, C++, C#, Python, Golang, Clojure)Conhecimento de programação orientada a objetos avançadaExperiência com metodologias XP e RUP ","permalink":"https://kotlin.dev.br/vagas/736u4vw66e5h47ed-amazon-desenvolvedor-de-software-mid-level/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Amazon está procurando um Desenvolvedor de Software Mid Level para integrar a equipe IES Latech Latam em Belo Horizonte. Você será responsável pelo desenvolvimento e manutenção de sistemas robustos utilizando as melhores práticas de engenharia de software.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações de software usando Kotlin, Java e outras linguagens modernas\u003c/li\u003e\u003cli\u003eTrabalhar com arquiteturas de microsserviços e Web Services\u003c/li\u003e\u003cli\u003eColaborar com equipes multidisciplinares em um ambiente Agile\u003c/li\u003e\u003cli\u003eImplementar soluções na plataforma AWS\u003c/li\u003e\u003cli\u003eParticipar de code reviews e melhorias contínuas\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sólida em desenvolvimento com Kotlin e/ou Java\u003c/li\u003e\u003cli\u003eConhecimento de Linux/UNIX e ferramentas de desenvolvimento\u003c/li\u003e\u003cli\u003eFamiliaridade com metodologias ágeis (SCRUM, Kanban)\u003c/li\u003e\u003cli\u003eExperiência com Web Services e APIs RESTful\u003c/li\u003e\u003cli\u003eConhecimento de AWS ou outras plataformas de cloud\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com múltiplas linguagens (C, C++, C#, Python, Golang, Clojure)\u003c/li\u003e\u003cli\u003eConhecimento de programação orientada a objetos avançada\u003c/li\u003e\u003cli\u003eExperiência com metodologias XP e RUP\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor de Software (Mid Level)"},{"content":"Sobre a vagaDesenvolvedor Mobile Android de nível médio em regime remoto na Colômbia.\nRequisitosExperiência com Kotlin e Java para desenvolvimento AndroidConhecimento em Kotlin CoroutinesExperiência com Dagger, Retrofit e RoomConhecimento em Gradle e Android ManifestArquitetura MVVM e Clean ArchitectureExperiência com AWS, Google Cloud ou Azure ","permalink":"https://kotlin.dev.br/vagas/4sed71kottoniwxm-capgemini-desenvolvedor-mobile-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eDesenvolvedor Mobile Android de nível médio em regime remoto na Colômbia.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin e Java para desenvolvimento Android\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin Coroutines\u003c/li\u003e\u003cli\u003eExperiência com Dagger, Retrofit e Room\u003c/li\u003e\u003cli\u003eConhecimento em Gradle e Android Manifest\u003c/li\u003e\u003cli\u003eArquitetura MVVM e Clean Architecture\u003c/li\u003e\u003cli\u003eExperiência com AWS, Google Cloud ou Azure\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Mobile Android"},{"content":"Sobre a vagaPosição de Desenvolvedor Mobile Android nível médio na Capgemini com trabalho remoto em Bogotá, Colômbia.\nResponsabilidadesDesenvolver e manter aplicações Android.Aplicar padrões de arquitetura como MVVM e Clean Architecture.Consumir APIs RESTful utilizando Retrofit.Implementar persistência de dados com Room.Utilizar Kotlin, Java, Dagger e Coroutines no desenvolvimento.RequisitosExperiência como desenvolvedor Android.Conhecimento em Kotlin e Java.Familiaridade com Dagger, Coroutines, Gradle, MVVM e Clean Architecture.Experiência com Retrofit, Room e APIs RESTful.Conhecimento em microsserviços e plataformas de nuvem como AWS, Google Cloud e Azure. ","permalink":"https://kotlin.dev.br/vagas/rhz0yetveleh7min-capgemini-desenvolvedor-mobile-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003ePosição de Desenvolvedor Mobile Android nível médio na Capgemini com trabalho remoto em Bogotá, Colômbia.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android.\u003c/li\u003e\u003cli\u003eAplicar padrões de arquitetura como MVVM e Clean Architecture.\u003c/li\u003e\u003cli\u003eConsumir APIs RESTful utilizando Retrofit.\u003c/li\u003e\u003cli\u003eImplementar persistência de dados com Room.\u003c/li\u003e\u003cli\u003eUtilizar Kotlin, Java, Dagger e Coroutines no desenvolvimento.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência como desenvolvedor Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin e Java.\u003c/li\u003e\u003cli\u003eFamiliaridade com Dagger, Coroutines, Gradle, MVVM e Clean Architecture.\u003c/li\u003e\u003cli\u003eExperiência com Retrofit, Room e APIs RESTful.\u003c/li\u003e\u003cli\u003eConhecimento em microsserviços e plataformas de nuvem como AWS, Google Cloud e Azure.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Mobile Android"},{"content":"Sobre a vagaA C6 Bank busca uma Pessoa Desenvolvedora Backend Sênior com experiência em Java e Kotlin para a área de Investments Engineering. Você atuará no desenvolvimento de soluções robustas e escaláveis utilizando tecnologias modernas.\nResponsabilidadesDesenvolver e manter aplicações backend em Java/KotlinTrabalhar com arquiteturas de microsserviçosImplementar soluções utilizando Spring BootParticipar de code reviews e mentoria de desenvolvedoresContribuir para a evolução da infraestrutura e práticas de engenhariaRequisitosExperiência sênior com Java e/ou KotlinConhecimento em Spring BootExperiência com bancos de dados relacionais e NoSQLFamiliaridade com sistemas de mensageriaConhecimento em CI/CD e controle de versão (GIT)Experiência com arquitetura em nuvemDiferenciaisExperiência prévia em instituições financeirasConhecimento em arquiteturas de microsserviçosContribuições em projetos open source ","permalink":"https://kotlin.dev.br/vagas/hrpyyyq2e6si3ye1-c6-bank-desenvolvedora-backend-senior-java-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA C6 Bank busca uma Pessoa Desenvolvedora Backend Sênior com experiência em Java e Kotlin para a área de Investments Engineering. Você atuará no desenvolvimento de soluções robustas e escaláveis utilizando tecnologias modernas.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações backend em Java/Kotlin\u003c/li\u003e\u003cli\u003eTrabalhar com arquiteturas de microsserviços\u003c/li\u003e\u003cli\u003eImplementar soluções utilizando Spring Boot\u003c/li\u003e\u003cli\u003eParticipar de code reviews e mentoria de desenvolvedores\u003c/li\u003e\u003cli\u003eContribuir para a evolução da infraestrutura e práticas de engenharia\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com Java e/ou Kotlin\u003c/li\u003e\u003cli\u003eConhecimento em Spring Boot\u003c/li\u003e\u003cli\u003eExperiência com bancos de dados relacionais e NoSQL\u003c/li\u003e\u003cli\u003eFamiliaridade com sistemas de mensageria\u003c/li\u003e\u003cli\u003eConhecimento em CI/CD e controle de versão (GIT)\u003c/li\u003e\u003cli\u003eExperiência com arquitetura em nuvem\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência prévia em instituições financeiras\u003c/li\u003e\u003cli\u003eConhecimento em arquiteturas de microsserviços\u003c/li\u003e\u003cli\u003eContribuições em projetos open source\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedora Backend Sênior Java/Kotlin"},{"content":"Sobre a vagaBig Moxi Games busca um Engenheiro de Serviços de nível médio a sênior para integrar sua equipe de forma remota.\nResponsabilidadesDesenvolver e manter serviços backend utilizando Unreal Engine.Implementar soluções com Protobuf, WebSockets e HTTPS.Gerenciar e operar em ambientes Linux.RequisitosExperiência com Java, Kotlin, C# ou Golang.Conhecimento em Unreal Engine.Experiência com Linux.TecnologiasJava, Kotlin, C#, Golang, Protobuf, WebSockets, HTTPS, Unreal Engine, Linux.\n","permalink":"https://kotlin.dev.br/vagas/pfvl08fqxh5xkl12-big-moxi-games-engenheiro-de-servicos-medio-a-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBig Moxi Games busca um Engenheiro de Serviços de nível médio a sênior para integrar sua equipe de forma remota.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend utilizando Unreal Engine.\u003c/li\u003e\u003cli\u003eImplementar soluções com Protobuf, WebSockets e HTTPS.\u003c/li\u003e\u003cli\u003eGerenciar e operar em ambientes Linux.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Java, Kotlin, C# ou Golang.\u003c/li\u003e\u003cli\u003eConhecimento em Unreal Engine.\u003c/li\u003e\u003cli\u003eExperiência com Linux.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cp\u003eJava, Kotlin, C#, Golang, Protobuf, WebSockets, HTTPS, Unreal Engine, Linux.\u003c/p\u003e","title":"Engenheiro de Serviços (Médio a Sênior)"},{"content":"Sobre a vagaEstamos contratando um Engenheiro de Sistemas de Jogo (Mid a Sênior) para a Big Moxi Games.\nA posição é remota e disponível para profissionais localizados em Porto Alegre ou Santiago.\nTecnologiasUnreal Engine 5Unreal Engine 4JVMJavaKotlinPythonBlueprintsRequisitosNível Mid a SêniorExperiência com Unreal EngineConhecimento em Kotlin, Java e Python ","permalink":"https://kotlin.dev.br/vagas/a9u0vptecwy3m51k-big-moxi-games-engenheiro-de-sistemas-de-jogo-mid-a-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eEstamos contratando um Engenheiro de Sistemas de Jogo (Mid a Sênior) para a Big Moxi Games.\u003c/p\u003e\u003cp\u003eA posição é remota e disponível para profissionais localizados em Porto Alegre ou Santiago.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eUnreal Engine 5\u003c/li\u003e\u003cli\u003eUnreal Engine 4\u003c/li\u003e\u003cli\u003eJVM\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003ePython\u003c/li\u003e\u003cli\u003eBlueprints\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eNível Mid a Sênior\u003c/li\u003e\u003cli\u003eExperiência com Unreal Engine\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Java e Python\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Sistemas de Jogo (Mid a Sênior)"},{"content":"Sobre a vagaBuscamos um Engenheiro de Software Pleno com experiência em Java e Kotlin para atuar remotamente no Brasil.\nResponsabilidadesDesenvolver aplicações backend em Java e Kotlin.Integrar sistemas utilizando Kafka, SQS e RabbitMQ.Administrar bancos de dados MySQL e PostgreSQL.Gerenciar infraestrutura com Docker, Kubernetes, ECS e serviços AWS como Lambda, API Gateway e SNS.Automatizar processos com Terraform, CloudFormation e Ansible.RequisitosExperiência média em desenvolvimento com Java.Conhecimento em Kotlin.Experiência com Kafka e mensageria.Conhecimento em Docker e Kubernetes.Familiaridade com AWS e IaC.DiferenciaisExperiência com Python e Golang. ","permalink":"https://kotlin.dev.br/vagas/jepq8od5nzbxv9ql-exadel-engenheiro-de-software-pleno-java/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Engenheiro de Software Pleno com experiência em Java e Kotlin para atuar remotamente no Brasil.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver aplicações backend em Java e Kotlin.\u003c/li\u003e\u003cli\u003eIntegrar sistemas utilizando Kafka, SQS e RabbitMQ.\u003c/li\u003e\u003cli\u003eAdministrar bancos de dados MySQL e PostgreSQL.\u003c/li\u003e\u003cli\u003eGerenciar infraestrutura com Docker, Kubernetes, ECS e serviços AWS como Lambda, API Gateway e SNS.\u003c/li\u003e\u003cli\u003eAutomatizar processos com Terraform, CloudFormation e Ansible.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência média em desenvolvimento com Java.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin.\u003c/li\u003e\u003cli\u003eExperiência com Kafka e mensageria.\u003c/li\u003e\u003cli\u003eConhecimento em Docker e Kubernetes.\u003c/li\u003e\u003cli\u003eFamiliaridade com AWS e IaC.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Python e Golang.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Software Pleno (Java)"},{"content":"Sobre a vagaEngenheiro de Software Staff Backend para a Plataforma de Crédito no iFood.\nResponsabilidadesDesenvolver e manter sistemas backend com Java e Kotlin.Trabalhar na Plataforma de Crédito.RequisitosExperiência em nível Staff.Domínio de Java e Kotlin.Atuação em backend.BenefíciosModelo remoto no Brasil.\n","permalink":"https://kotlin.dev.br/vagas/20xtweg61f7t0otn-ifood-engenheiro-de-software-staff-backend-plataforma-de-credit/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eEngenheiro de Software Staff Backend para a Plataforma de Crédito no iFood.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter sistemas backend com Java e Kotlin.\u003c/li\u003e\u003cli\u003eTrabalhar na Plataforma de Crédito.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em nível Staff.\u003c/li\u003e\u003cli\u003eDomínio de Java e Kotlin.\u003c/li\u003e\u003cli\u003eAtuação em backend.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eBenefícios\u003c/h3\u003e\u003cp\u003eModelo remoto no Brasil.\u003c/p\u003e","title":"Engenheiro de Software Staff - Backend (Plataforma de Crédito)"},{"content":"Sobre a vagaBuscamos um Backend Engineer IC2 para integrar nosso time de desenvolvimento. Você trabalhará com tecnologias modernas na plataforma JVM, contribuindo para sistemas escaláveis e de alta performance.\nResponsabilidadesDesenvolver e manter serviços backend em Kotlin e Spring BootTrabalhar com bancos de dados SQL e PostgreSQLImplementar soluções com Redis e Kafka para processamento de dadosColaborar em pipelines CI/CD e containerização com DockerParticipar de arquitetura e deployment em KubernetesRequisitosExperiência com linguagens JVM (Kotlin, Java 11 ou Scala)Conhecimento em Spring Boot e desenvolvimento backendFamiliaridade com PostgreSQL e SQLConhecimento básico de Docker e CI/CDComunicação clara e capacidade de trabalho em equipeDiferenciaisExperiência com Kubernetes e orquestração de containersConhecimento em Kafka e arquiteturas event-drivenExperiência com Redis ","permalink":"https://kotlin.dev.br/vagas/5q6ovu9zt6cdg8xd-addi-backend-engineer-ic2/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Backend Engineer IC2 para integrar nosso time de desenvolvimento. Você trabalhará com tecnologias modernas na plataforma JVM, contribuindo para sistemas escaláveis e de alta performance.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend em Kotlin e Spring Boot\u003c/li\u003e\u003cli\u003eTrabalhar com bancos de dados SQL e PostgreSQL\u003c/li\u003e\u003cli\u003eImplementar soluções com Redis e Kafka para processamento de dados\u003c/li\u003e\u003cli\u003eColaborar em pipelines CI/CD e containerização com Docker\u003c/li\u003e\u003cli\u003eParticipar de arquitetura e deployment em Kubernetes\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com linguagens JVM (Kotlin, Java 11 ou Scala)\u003c/li\u003e\u003cli\u003eConhecimento em Spring Boot e desenvolvimento backend\u003c/li\u003e\u003cli\u003eFamiliaridade com PostgreSQL e SQL\u003c/li\u003e\u003cli\u003eConhecimento básico de Docker e CI/CD\u003c/li\u003e\u003cli\u003eComunicação clara e capacidade de trabalho em equipe\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kubernetes e orquestração de containers\u003c/li\u003e\u003cli\u003eConhecimento em Kafka e arquiteturas event-driven\u003c/li\u003e\u003cli\u003eExperiência com Redis\u003c/li\u003e\u003c/ul\u003e","title":"Backend Engineer IC2"},{"content":"Sobre a vagaCI\u0026T busca Desenvolvedor Mobile Pleno para atuar de forma remota no Brasil.\nRequisitosExperiência com Kotlin e Kotlin CoroutinesDomínio de Jetpack Compose e KoinConhecimento em Firebase, Retrofit e Android WebViewFamiliaridade com Swift e Objective-CTecnologiasKotlinKotlin CoroutinesJetpack ComposeKoinFirebaseRetrofitSwiftObjective-C ","permalink":"https://kotlin.dev.br/vagas/x2kx7bivj25dg999-ci-t-desenvolvedor-mobile-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eCI\u0026T busca Desenvolvedor Mobile Pleno para atuar de forma remota no Brasil.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin e Kotlin Coroutines\u003c/li\u003e\u003cli\u003eDomínio de Jetpack Compose e Koin\u003c/li\u003e\u003cli\u003eConhecimento em Firebase, Retrofit e Android WebView\u003c/li\u003e\u003cli\u003eFamiliaridade com Swift e Objective-C\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eKotlin Coroutines\u003c/li\u003e\u003cli\u003eJetpack Compose\u003c/li\u003e\u003cli\u003eKoin\u003c/li\u003e\u003cli\u003eFirebase\u003c/li\u003e\u003cli\u003eRetrofit\u003c/li\u003e\u003cli\u003eSwift\u003c/li\u003e\u003cli\u003eObjective-C\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Mobile Pleno"},{"content":"Sobre a vagaEstamos buscando um Engenheiro Android Sênior para uma posição remota na América do Norte ou América do Sul.\nRequisitosExperiência em desenvolvimento Android usando KotlinAplicação de MVVM e Clean ArchitectureUso de Jetpack Compose e componentes do Android JetpackSuporte para Android 9.0 (API level 28) ou superiorFerramentasUtilização de Copilot, ChatGPT e Claude Code.\n","permalink":"https://kotlin.dev.br/vagas/zmfjqjapx4rzv910-nortal-engenheiro-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eEstamos buscando um Engenheiro Android Sênior para uma posição remota na América do Norte ou América do Sul.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento Android usando Kotlin\u003c/li\u003e\u003cli\u003eAplicação de MVVM e Clean Architecture\u003c/li\u003e\u003cli\u003eUso de Jetpack Compose e componentes do Android Jetpack\u003c/li\u003e\u003cli\u003eSuporte para Android 9.0 (API level 28) ou superior\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFerramentas\u003c/h3\u003e\u003cp\u003eUtilização de Copilot, ChatGPT e Claude Code.\u003c/p\u003e","title":"Engenheiro Android Sênior"},{"content":"Sobre a vagaEngenheiro de Software Backend Sênior na iFood em Osasco ou Brasil, em regime onsite.\nRequisitosExperiência sênior em desenvolvimento backend.Conhecimento em Kotlin e Java.TecnologiasAWSJavaKotlinRustLinuxKubernetesDockerKafkaSQSSNSRabbitMQTerraformHelmDatabricksData Lake ","permalink":"https://kotlin.dev.br/vagas/2zc7gsvcxmsp6anz-ifood-engenheiro-de-software-backend-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eEngenheiro de Software Backend Sênior na iFood em Osasco ou Brasil, em regime onsite.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento backend.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin e Java.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eRust\u003c/li\u003e\u003cli\u003eLinux\u003c/li\u003e\u003cli\u003eKubernetes\u003c/li\u003e\u003cli\u003eDocker\u003c/li\u003e\u003cli\u003eKafka\u003c/li\u003e\u003cli\u003eSQS\u003c/li\u003e\u003cli\u003eSNS\u003c/li\u003e\u003cli\u003eRabbitMQ\u003c/li\u003e\u003cli\u003eTerraform\u003c/li\u003e\u003cli\u003eHelm\u003c/li\u003e\u003cli\u003eDatabricks\u003c/li\u003e\u003cli\u003eData Lake\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Software Backend Sênior"},{"content":"Sobre a vagaGerente de Engenharia de Software na Stone. A vaga é remota no Brasil.\nResponsabilidadesLiderança de times de engenharia de software.Gestão de projetos utilizando tecnologias como Kotlin e Golang.Implementação de práticas de CI/CD e DevSecOps.RequisitosExperiência em gerenciamento de equipes de software.Conhecimento avançado em Kotlin.Familiaridade com Golang, Elixir, .NET, Android e iOS.Conhecimento em Kotlin Multiplatform e Compose Multiplatform.DiferenciaisExperiência com métricas DORA.BenefíciosModelo de trabalho remoto. ","permalink":"https://kotlin.dev.br/vagas/ylmszx0xgbbq7dek-stone-gerente-de-engenharia-de-software-i/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eGerente de Engenharia de Software na Stone. A vaga é remota no Brasil.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLiderança de times de engenharia de software.\u003c/li\u003e\u003cli\u003eGestão de projetos utilizando tecnologias como Kotlin e Golang.\u003c/li\u003e\u003cli\u003eImplementação de práticas de CI/CD e DevSecOps.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em gerenciamento de equipes de software.\u003c/li\u003e\u003cli\u003eConhecimento avançado em Kotlin.\u003c/li\u003e\u003cli\u003eFamiliaridade com Golang, Elixir, .NET, Android e iOS.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin Multiplatform e Compose Multiplatform.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com métricas DORA.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eBenefícios\u003c/h3\u003e\u003cul\u003e\u003cli\u003eModelo de trabalho remoto.\u003c/li\u003e\u003c/ul\u003e","title":"Gerente de Engenharia de Software I"},{"content":"Sobre a vagaBuscamos um Desenvolvedor Android Sênior experiente em Kotlin para integrar nosso time de desenvolvimento. Você será responsável por arquitetar e implementar soluções mobile de alta qualidade, trabalhando com as tecnologias mais modernas do ecossistema Android.\nResponsabilidadesDesenvolver e manter aplicações Android robustas utilizando KotlinImplementar interfaces modernas com Jetpack ComposeArquitetar soluções seguindo padrões MVVM e boas práticasConfigurar e otimizar pipelines de build com GradleAutomatizar processos de deployment para Play Store com FastlaneColaborar com equipes multidisciplinaresRequisitosExperiência sênior em desenvolvimento Android com KotlinDomínio de Jetpack e Jetpack ComposeConhecimento sólido em arquitetura MVVMExperiência com Gradle e ferramentas de buildFamiliaridade com Fastlane e processos de CI/CDDiferenciaisExperiência com React Native ou FlutterConhecimento de publicação na Play StoreContribuições a projetos open source ","permalink":"https://kotlin.dev.br/vagas/5gfu6ocy3p55cc6t-inter-co-desenvolvedor-android-senior-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Desenvolvedor Android Sênior experiente em Kotlin para integrar nosso time de desenvolvimento. Você será responsável por arquitetar e implementar soluções mobile de alta qualidade, trabalhando com as tecnologias mais modernas do ecossistema Android.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android robustas utilizando Kotlin\u003c/li\u003e\u003cli\u003eImplementar interfaces modernas com Jetpack Compose\u003c/li\u003e\u003cli\u003eArquitetar soluções seguindo padrões MVVM e boas práticas\u003c/li\u003e\u003cli\u003eConfigurar e otimizar pipelines de build com Gradle\u003c/li\u003e\u003cli\u003eAutomatizar processos de deployment para Play Store com Fastlane\u003c/li\u003e\u003cli\u003eColaborar com equipes multidisciplinares\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android com Kotlin\u003c/li\u003e\u003cli\u003eDomínio de Jetpack e Jetpack Compose\u003c/li\u003e\u003cli\u003eConhecimento sólido em arquitetura MVVM\u003c/li\u003e\u003cli\u003eExperiência com Gradle e ferramentas de build\u003c/li\u003e\u003cli\u003eFamiliaridade com Fastlane e processos de CI/CD\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com React Native ou Flutter\u003c/li\u003e\u003cli\u003eConhecimento de publicação na Play Store\u003c/li\u003e\u003cli\u003eContribuições a projetos open source\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android Sênior (Kotlin)"},{"content":"Sobre a vagaA Braze está contratando um Líder de Engajamento de Suporte para trabalhar em modelo híbrido em diversas cidades, incluindo São Paulo.\nRequisitosConhecimento em Kotlin, Java, JavaScript, Ruby e SwiftExperiência com Salesforce, Zendesk, SQL, APIs e ferramentas como Postman, Snowflake, Kibana e DatadogNível intermediárioTech StackKotlin, Java, JavaScript, Ruby, Swift, SQL, Salesforce, Zendesk, Braze\n","permalink":"https://kotlin.dev.br/vagas/wevbrib5ikpvcuhy-braze-lider-de-engajamento-de-suporte/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Braze está contratando um Líder de Engajamento de Suporte para trabalhar em modelo híbrido em diversas cidades, incluindo São Paulo.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eConhecimento em Kotlin, Java, JavaScript, Ruby e Swift\u003c/li\u003e\u003cli\u003eExperiência com Salesforce, Zendesk, SQL, APIs e ferramentas como Postman, Snowflake, Kibana e Datadog\u003c/li\u003e\u003cli\u003eNível intermediário\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTech Stack\u003c/h3\u003e\u003cp\u003eKotlin, Java, JavaScript, Ruby, Swift, SQL, Salesforce, Zendesk, Braze\u003c/p\u003e","title":"Líder de Engajamento de Suporte"},{"content":"Sobre a vagaProcuramos um engenheiro backend sênior com expertise em Python, Kotlin e JVM para integrar nosso time na Software Mind. Você atuará de forma remota, contribuindo para soluções backend escaláveis e modernas.\nResponsabilidadesDesenvolver e manter aplicações backend em Python e KotlinTrabalhar com arquitetura JVM e otimização de performanceImplementar infraestrutura em AWS (EC2, ECS) e CI/CD com Jenkins e AWS CodePipelineGerenciar containers com Docker e infraestrutura como código com TerraformMonitorar aplicações com New Relic e garantir qualidade de serviçoRequisitosExperiência sênior com Python e KotlinConhecimento profundo de JVM e ecosistema JavaExpertise em AWS (SDK, EC2, ECS)Proficiência em Docker, Terraform e CI/CD (Jenkins, AWS CodePipeline)Experiência com ferramentas de build (Maven, Gradle)Domínio de scripting em BashConhecimento de monitoramento com New RelicDiferenciaisExperiência com Boto3 e Boto2Conhecimento de pyproject.toml e pipHistórico em projetos de infraestrutura em larga escala ","permalink":"https://kotlin.dev.br/vagas/g5npr9rd6qtr0ehg-software-mind-senior-backend-engineer-python-kotlin-jvm/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eProcuramos um engenheiro backend sênior com expertise em Python, Kotlin e JVM para integrar nosso time na Software Mind. Você atuará de forma remota, contribuindo para soluções backend escaláveis e modernas.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações backend em Python e Kotlin\u003c/li\u003e\u003cli\u003eTrabalhar com arquitetura JVM e otimização de performance\u003c/li\u003e\u003cli\u003eImplementar infraestrutura em AWS (EC2, ECS) e CI/CD com Jenkins e AWS CodePipeline\u003c/li\u003e\u003cli\u003eGerenciar containers com Docker e infraestrutura como código com Terraform\u003c/li\u003e\u003cli\u003eMonitorar aplicações com New Relic e garantir qualidade de serviço\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com Python e Kotlin\u003c/li\u003e\u003cli\u003eConhecimento profundo de JVM e ecosistema Java\u003c/li\u003e\u003cli\u003eExpertise em AWS (SDK, EC2, ECS)\u003c/li\u003e\u003cli\u003eProficiência em Docker, Terraform e CI/CD (Jenkins, AWS CodePipeline)\u003c/li\u003e\u003cli\u003eExperiência com ferramentas de build (Maven, Gradle)\u003c/li\u003e\u003cli\u003eDomínio de scripting em Bash\u003c/li\u003e\u003cli\u003eConhecimento de monitoramento com New Relic\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Boto3 e Boto2\u003c/li\u003e\u003cli\u003eConhecimento de pyproject.toml e pip\u003c/li\u003e\u003cli\u003eHistórico em projetos de infraestrutura em larga escala\u003c/li\u003e\u003c/ul\u003e","title":"Senior Backend Engineer (Python + Kotlin + JVM)"},{"content":"Sobre a vagaProcuramos um Support Engagement Lead para liderar iniciativas de engajamento e excelência técnica no suporte ao cliente. Você trabalhará em um ambiente híbrido, colaborando com times globais e gerenciando estratégias de suporte de alto impacto.\nResponsabilidadesLiderar e otimizar processos de engajamento do suporte técnicoColaborar com equipes de produto e engenharia usando APIs e ferramentas analíticasAnalisar dados de suporte com SQL, Snowflake e ferramentas de BI como Kibana e DatadogGerenciar relacionamento com clientes e stakeholders globaisContribuir para melhorias contínuas na experiência do clienteRequisitosExperiência comprovada em liderança de suporte técnico ou engajamento de clientesConhecimento sólido de APIs e integração com plataformas como Salesforce e ZendeskCompetência em SQL e análise de dadosFamiliaridade com ferramentas de observabilidade e BI (Kibana, Datadog)Experiência com Kotlin, Java, Swift ou linguagens similares é desejávelCapacidade de trabalhar em ambiente remoto e híbrido com times distribuídasDiferenciaisExperiência com Braze ou plataformas de engajamento similaresConhecimento de Postman, Snowsight e ferramentas de desenvolvimentoFluência em HTML, CSS e JavaScriptExperiência com Ruby ou outras linguagens de scriptingBenefíciosAmbiente de trabalho híbrido com flexibilidade globalOportunidade de trabalhar com tecnologia de ponta em engajamento do clienteColaboração com times internacionais ","permalink":"https://kotlin.dev.br/vagas/8efclphxyg6m5mv2-braze-support-engagement-lead/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eProcuramos um Support Engagement Lead para liderar iniciativas de engajamento e excelência técnica no suporte ao cliente. Você trabalhará em um ambiente híbrido, colaborando com times globais e gerenciando estratégias de suporte de alto impacto.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLiderar e otimizar processos de engajamento do suporte técnico\u003c/li\u003e\u003cli\u003eColaborar com equipes de produto e engenharia usando APIs e ferramentas analíticas\u003c/li\u003e\u003cli\u003eAnalisar dados de suporte com SQL, Snowflake e ferramentas de BI como Kibana e Datadog\u003c/li\u003e\u003cli\u003eGerenciar relacionamento com clientes e stakeholders globais\u003c/li\u003e\u003cli\u003eContribuir para melhorias contínuas na experiência do cliente\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência comprovada em liderança de suporte técnico ou engajamento de clientes\u003c/li\u003e\u003cli\u003eConhecimento sólido de APIs e integração com plataformas como Salesforce e Zendesk\u003c/li\u003e\u003cli\u003eCompetência em SQL e análise de dados\u003c/li\u003e\u003cli\u003eFamiliaridade com ferramentas de observabilidade e BI (Kibana, Datadog)\u003c/li\u003e\u003cli\u003eExperiência com Kotlin, Java, Swift ou linguagens similares é desejável\u003c/li\u003e\u003cli\u003eCapacidade de trabalhar em ambiente remoto e híbrido com times distribuídas\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Braze ou plataformas de engajamento similares\u003c/li\u003e\u003cli\u003eConhecimento de Postman, Snowsight e ferramentas de desenvolvimento\u003c/li\u003e\u003cli\u003eFluência em HTML, CSS e JavaScript\u003c/li\u003e\u003cli\u003eExperiência com Ruby ou outras linguagens de scripting\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eBenefícios\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAmbiente de trabalho híbrido com flexibilidade global\u003c/li\u003e\u003cli\u003eOportunidade de trabalhar com tecnologia de ponta em engajamento do cliente\u003c/li\u003e\u003cli\u003eColaboração com times internacionais\u003c/li\u003e\u003c/ul\u003e","title":"Support Engagement Lead"},{"content":"Sobre a vagaA Braze busca um Support Engagement Lead para liderar iniciativas de engajamento com clientes, resolvendo desafios técnicos complexos e orientando implementações de plataforma de customer engagement em escala global.\nResponsabilidadesGerenciar campanhas de engagement e comunicação com clientes de alto valorResolver problemas técnicos relacionados a APIs, integrações e plataformas de dadosOrientar clientes na implementação e otimização de soluções BrazeColaborar com times de produto e engenharia para melhorias contínuasDocumentar soluções e boas práticas para a base de conhecimentoRequisitosExperiência sólida com ferramentas de customer engagement (Salesforce, Zendesk)Conhecimento prático de APIs, SQL e análise de dadosFamiliaridade com plataformas como Snowflake, Kibana ou DatadogCompetência técnica em Kotlin, JavaScript, HTML/CSS ou RubyExcelentes habilidades de comunicação e resolução de problemasExperiência com Postman ou ferramentas similares de testes de APIDiferenciaisExperiência prévia com Braze ou plataformas similares de marketing automationConhecimento de Swift ou JavaHistórico de sucesso em suporte técnico ou customer successLocalizaçãoSão Francisco, Nova York, Austin, Chicago, Berlim, Bucareste, Dubai, Jacarta, Londres, Paris, São Paulo, Singapura, Seul, Sydney ou Tóquio (híbrido).\n","permalink":"https://kotlin.dev.br/vagas/xnwjoepr7aii3xek-braze-support-engagement-lead/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Braze busca um Support Engagement Lead para liderar iniciativas de engajamento com clientes, resolvendo desafios técnicos complexos e orientando implementações de plataforma de customer engagement em escala global.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eGerenciar campanhas de engagement e comunicação com clientes de alto valor\u003c/li\u003e\u003cli\u003eResolver problemas técnicos relacionados a APIs, integrações e plataformas de dados\u003c/li\u003e\u003cli\u003eOrientar clientes na implementação e otimização de soluções Braze\u003c/li\u003e\u003cli\u003eColaborar com times de produto e engenharia para melhorias contínuas\u003c/li\u003e\u003cli\u003eDocumentar soluções e boas práticas para a base de conhecimento\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sólida com ferramentas de customer engagement (Salesforce, Zendesk)\u003c/li\u003e\u003cli\u003eConhecimento prático de APIs, SQL e análise de dados\u003c/li\u003e\u003cli\u003eFamiliaridade com plataformas como Snowflake, Kibana ou Datadog\u003c/li\u003e\u003cli\u003eCompetência técnica em Kotlin, JavaScript, HTML/CSS ou Ruby\u003c/li\u003e\u003cli\u003eExcelentes habilidades de comunicação e resolução de problemas\u003c/li\u003e\u003cli\u003eExperiência com Postman ou ferramentas similares de testes de API\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência prévia com Braze ou plataformas similares de marketing automation\u003c/li\u003e\u003cli\u003eConhecimento de Swift ou Java\u003c/li\u003e\u003cli\u003eHistórico de sucesso em suporte técnico ou customer success\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocalização\u003c/h3\u003e\u003cp\u003eSão Francisco, Nova York, Austin, Chicago, Berlim, Bucareste, Dubai, Jacarta, Londres, Paris, São Paulo, Singapura, Seul, Sydney ou Tóquio (híbrido).\u003c/p\u003e","title":"Support Engagement Lead"},{"content":"Widgets Android parecem pequenos detalhes de interface, mas costumam ser uma das formas mais fortes de retenção quando o produto tem informação recorrente: tarefas do dia, saldo, previsão, treino, entrega, hábito, checklist, métricas ou status de sincronização. Em 2026, criar widgets com Kotlin ficou mais natural graças ao Jetpack Glance, que aproxima a experiência de desenvolvimento do modelo declarativo do Compose sem exigir que você escreva tudo diretamente com RemoteViews.\nGlance não é \u0026ldquo;Compose completo na tela inicial\u0026rdquo;. Ele é uma camada declarativa para gerar widgets compatíveis com o sistema de AppWidget do Android. Isso significa que você escreve código com uma aparência familiar para quem usa Jetpack Compose, mas ainda precisa respeitar as limitações da tela inicial: poucas interações, atualização controlada, layout mais restrito, tamanho variável e cuidado grande com bateria.\nEste guia mostra como pensar um widget Android moderno com Kotlin: quando ele faz sentido, como organizar módulos, como guardar estado, como atualizar dados, onde entra o WorkManager e quais erros costumam quebrar a experiência. Se você está montando a base do app, leia também WorkManager com Kotlin no Android, DataStore Preferences com Kotlin e Modularização Android com Kotlin e Compose.\nQuando um widget vale a pena O erro comum é criar widget porque o app \u0026ldquo;precisa de presença\u0026rdquo; na tela inicial. Presença sozinha não sustenta uso. Um widget vale a pena quando ele responde a uma pergunta frequente sem exigir que a pessoa abra o app.\nBons casos de uso incluem:\npróxima tarefa ou próximo evento; resumo financeiro simples; status de entrega ou pedido; previsão do tempo resumida; hábito do dia; contador de estudos, treino ou foco; atalhos para ações recorrentes; métrica operacional de um app interno. Casos ruins incluem widgets que apenas repetem a home do aplicativo, banners promocionais sem utilidade ou telas que dependem de muita navegação. A tela inicial não é lugar para fluxo complexo. Ela funciona melhor como painel de contexto e porta de entrada para uma ação específica.\nEstrutura básica com Glance Um widget Glance normalmente combina três peças: uma classe GlanceAppWidget, um receiver GlanceAppWidgetReceiver e alguma fonte de estado. A classe do widget descreve o conteúdo. O receiver conecta o widget ao sistema Android. A fonte de estado alimenta o layout.\nUm exemplo mínimo fica assim:\nclass HabitoDoDiaWidget : GlanceAppWidget() { override suspend fun provideGlance(context: Context, id: GlanceId) { provideContent { GlanceTheme { Column( modifier = GlanceModifier .fillMaxSize() .padding(16.dp), verticalAlignment = Alignment.CenterVertically, horizontalAlignment = Alignment.CenterHorizontally, ) { Text( text = \u0026#34;Hábito de hoje\u0026#34;, style = TextStyle(fontWeight = FontWeight.Bold), ) Spacer(GlanceModifier.height(8.dp)) Text(text = \u0026#34;Beber água antes das 10h\u0026#34;) } } } } } class HabitoDoDiaWidgetReceiver : GlanceAppWidgetReceiver() { override val glanceAppWidget: GlanceAppWidget = HabitoDoDiaWidget() } O manifesto aponta para o receiver e para o arquivo de configuração do AppWidget. Essa parte continua parecida com widgets tradicionais porque o Android precisa descobrir o widget antes de executar seu código Kotlin.\n\u0026lt;receiver android:name=\u0026#34;.widgets.HabitoDoDiaWidgetReceiver\u0026#34; android:exported=\u0026#34;true\u0026#34;\u0026gt; \u0026lt;intent-filter\u0026gt; \u0026lt;action android:name=\u0026#34;android.appwidget.action.APPWIDGET_UPDATE\u0026#34; /\u0026gt; \u0026lt;/intent-filter\u0026gt; \u0026lt;meta-data android:name=\u0026#34;android.appwidget.provider\u0026#34; android:resource=\u0026#34;@xml/habito_do_dia_widget_info\u0026#34; /\u0026gt; \u0026lt;/receiver\u0026gt; Layout não é tela Compose normal A maior armadilha para quem vem do Compose é esquecer que Glance gera um widget de tela inicial, não uma Activity. Você não deve esperar a mesma liberdade de layout, animação, navegação, gesto ou estado efêmero.\nEm vez de tentar reproduzir uma tela inteira, desenhe uma versão reduzida:\numa informação principal; uma informação secundária; uma ação clara; um estado de erro ou vazio; um visual legível em tamanhos pequenos. Pense em blocos como Column, Row, Text, Image, Button e Spacer. Evite densidade excessiva. Um widget pequeno precisa ser entendido em menos de dois segundos.\nPara apps que já usam design system em Compose, vale criar uma camada de tokens compartilhados: nomes de cores, espaçamentos, textos e decisões de conteúdo. Mas não tente reutilizar todos os componentes Compose diretamente. O ideal é compartilhar intenção visual, não acoplar o widget ao mesmo componente da tela interna.\nEstado com DataStore ou banco local Widget bom precisa carregar rápido e funcionar mesmo quando o app não está aberto. Por isso, ele deve ler de uma fonte local simples. Para preferências e pequenos resumos, DataStore costuma ser suficiente. Para listas, histórico ou dados estruturados, Room ou SQLDelight fazem mais sentido.\nUm padrão saudável é manter um WidgetStateRepository separado da UI principal:\ndata class ResumoWidget( val titulo: String, val detalhe: String, val atualizadoEm: Instant, ) class WidgetStateRepository( private val dataStore: DataStore\u0026lt;Preferences\u0026gt;, ) { val resumo: Flow\u0026lt;ResumoWidget\u0026gt; = dataStore.data.map { prefs -\u0026gt; ResumoWidget( titulo = prefs[stringPreferencesKey(\u0026#34;widget_titulo\u0026#34;)] ?: \u0026#34;Sem dados\u0026#34;, detalhe = prefs[stringPreferencesKey(\u0026#34;widget_detalhe\u0026#34;)] ?: \u0026#34;Abra o app para configurar\u0026#34;, atualizadoEm = Instant.fromEpochMilliseconds( prefs[longPreferencesKey(\u0026#34;widget_atualizado_em\u0026#34;)] ?: 0L, ), ) } } Esse repositório não deve depender de Activity, NavController nem estado de tela. Ele precisa ser fácil de chamar a partir do app, de um worker ou do próprio widget. Em projetos modularizados, uma organização comum é :feature:widget dependendo de :core:model, :core:datastore e, quando necessário, :core:sync.\nAtualização com WorkManager Widgets não devem acordar rede a todo momento. O sistema limita atualizações e o usuário percebe quando um app consome bateria por causa de painel decorativo. A regra prática é sincronizar dados no app ou em background controlado, salvar um resumo local e pedir atualização do widget depois.\nWorkManager encaixa bem quando o dado pode ser atualizado em janela flexível:\nclass AtualizarWidgetWorker( context: Context, params: WorkerParameters, private val repository: WidgetStateRepository, ) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { return runCatching { repository.sincronizarResumoRemoto() HabitoDoDiaWidget().updateAll(applicationContext) }.fold( onSuccess = { Result.success() }, onFailure = { Result.retry() }, ) } } Para dados urgentes, como entrega em rota ou alerta crítico, avalie notificações em vez de forçar widgets como canal de tempo real. Widget é melhor para contexto persistente; notificação é melhor para evento que exige atenção.\nClique e navegação A interação mais importante de muitos widgets é abrir o app já na tela certa. Em Glance, você pode usar ações para iniciar uma Activity ou enviar um broadcast. O widget não deve exigir que o usuário abra a home e procure manualmente o próximo passo.\nText( text = \u0026#34;Ver detalhes\u0026#34;, modifier = GlanceModifier.clickable( actionStartActivity\u0026lt;MainActivity\u0026gt;( parameters = actionParametersOf( ActionParameters.Key\u0026lt;String\u0026gt;(\u0026#34;destino\u0026#34;) to \u0026#34;habitos\u0026#34;, ), ), ), ) No app, trate esse destino como deep link interno. Se você já usa App Links ou Navigation Compose, mantenha uma rota estável para o widget. Isso evita que uma refatoração de navegação quebre atalhos instalados na tela inicial.\nEstados que precisam aparecer Um widget de produção deve ter pelo menos quatro estados planejados:\nSem configuração: usuário adicionou o widget, mas ainda não escolheu conta, hábito ou lista. Com dados: resumo principal está pronto. Sem conexão ou erro: último dado válido existe, mas a atualização falhou. Conta desconectada: usuário saiu do app ou perdeu sessão. Não esconda falha como se fosse dado atualizado. Mostre algo como \u0026ldquo;Atualizado ontem\u0026rdquo; ou \u0026ldquo;Abra o app para reconectar\u0026rdquo;. Transparência evita decisões erradas e reduz suporte.\nTestes e validação prática Testar widget é menos confortável que testar ViewModel, mas ainda dá para validar bastante coisa. Separe lógica de seleção de dados em classes puras, teste o repositório local, teste o worker e faça uma checklist manual em emulador ou aparelho real.\nAntes de publicar, valide:\nwidget pequeno, médio e grande; tema claro e escuro; fonte aumentada nas configurações de acessibilidade; usuário deslogado; modo avião; atualização depois de abrir o app; atualização depois de worker; clique abrindo a tela correta; remoção e adição do widget novamente. Também vale medir uso. Se o widget existe para aumentar retenção, acompanhe eventos como adição, clique e atualização bem-sucedida. Um app Kotlin que usa analytics já pode padronizar isso em um módulo :core:analytics sem espalhar chamadas pela UI.\nErros comuns O primeiro erro é colocar informação demais. Widget cheio vira ruído visual. O segundo é buscar rede diretamente durante a renderização, criando lentidão e falhas intermitentes. O terceiro é não pensar em sessão expirada: o widget continua mostrando dado antigo e passa falsa confiança.\nOutro erro é tratar Glance como substituto de uma tela Compose. Se você precisa de lista longa, filtros, abas e formulário, abra o app. O widget deve ser o resumo e o atalho, não o produto inteiro.\nPor fim, cuidado com compatibilidade. Diferentes launchers podem renderizar detalhes de forma ligeiramente diferente. Teste pelo menos no launcher padrão do emulador e em um aparelho real quando o widget for parte importante da proposta de valor.\nOnde Glance entra na arquitetura Em um app Android moderno, o widget deve ficar próximo da camada de experiência, mas longe das telas internas. Uma estrutura possível:\n:app :feature:home :feature:widget :core:model :core:datastore :core:sync :core:analytics O módulo :feature:widget renderiza Glance e traduz estado local para UI de tela inicial. O :core:sync busca dados. O :core:datastore ou :core:database persiste o resumo. O :core:analytics mede clique e atualização. Isso evita que o widget dependa de ViewModels de tela ou que o app principal precise conhecer detalhes de AppWidget.\nPara times que trabalham também com backend Kotlin, a lógica de resumo pode ser pensada como contrato de produto: o servidor entrega um payload pequeno e estável, e o Android decide como mostrá-lo no widget. Quando o mesmo produto tem jobs, sincronização ou automações fora do Android, vale comparar como outras stacks estruturam workers. O guia de Celery em Python para tarefas em background ajuda a pensar em filas e retries do lado servidor sem misturar isso com a camada mobile.\nConclusão Glance torna widgets Android muito mais agradáveis para equipes Kotlin que já pensam de forma declarativa, mas a disciplina de produto continua sendo a parte mais importante. Um widget útil não é uma miniatura do app. Ele é uma resposta rápida, confiável e acionável para uma necessidade recorrente.\nComece pequeno: um resumo local, uma ação clara, atualização controlada e estados honestos. Depois conecte com WorkManager, DataStore, analytics e navegação profunda. Se o widget realmente reduz atrito, ele vira um ponto de contato diário com o usuário. Se ele só replica tela, vira decoração. Em Android com Kotlin, essa diferença aparece rápido na retenção, na bateria e na qualidade percebida do produto.\n","permalink":"https://kotlin.dev.br/blog/glance-widgets-android-kotlin-2026/","summary":"\u003cp\u003eWidgets Android parecem pequenos detalhes de interface, mas costumam ser uma das formas mais fortes de retenção quando o produto tem informação recorrente: tarefas do dia, saldo, previsão, treino, entrega, hábito, checklist, métricas ou status de sincronização. Em 2026, criar widgets com Kotlin ficou mais natural graças ao \u003cstrong\u003eJetpack Glance\u003c/strong\u003e, que aproxima a experiência de desenvolvimento do modelo declarativo do Compose sem exigir que você escreva tudo diretamente com \u003ccode\u003eRemoteViews\u003c/code\u003e.\u003c/p\u003e","title":"Glance Widgets no Android com Kotlin em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaO Albert Einstein busca Desenvolvedor(a) Mobile Pleno para atuar em aplicações mobile, em modelo híbrido em São Paulo, na região da Faria Lima.\nStack e atuaçãoDesenvolvimento mobile com Flutter e React Native.Integração com APIs REST e serviços Firebase.Uso de Git e práticas de CI/CD.Contato com tecnologias nativas como Kotlin e Swift.Acompanhamento de operação e suporte com ferramentas como ServiceNow e Dynatrace.RequisitosExperiência em desenvolvimento de aplicações mobile.Conhecimento em Flutter, React Native, Firebase, REST e Git.Familiaridade com pipelines de CI/CD.Disponibilidade para atuação híbrida em São Paulo. ","permalink":"https://kotlin.dev.br/vagas/cczmn0xd7nxu0vck-albert-einstein-desenvolvedor-a-mobile-pleno-flutter-react-nati/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO Albert Einstein busca Desenvolvedor(a) Mobile Pleno para atuar em aplicações mobile, em modelo híbrido em São Paulo, na região da Faria Lima.\u003c/p\u003e\u003ch3\u003eStack e atuação\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolvimento mobile com \u003cstrong\u003eFlutter\u003c/strong\u003e e \u003cstrong\u003eReact Native\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eIntegração com APIs \u003cstrong\u003eREST\u003c/strong\u003e e serviços Firebase.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eGit\u003c/strong\u003e e práticas de \u003cstrong\u003eCI/CD\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eContato com tecnologias nativas como \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eSwift\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eAcompanhamento de operação e suporte com ferramentas como ServiceNow e Dynatrace.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento de aplicações mobile.\u003c/li\u003e\u003cli\u003eConhecimento em Flutter, React Native, Firebase, REST e Git.\u003c/li\u003e\u003cli\u003eFamiliaridade com pipelines de CI/CD.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação híbrida em São Paulo.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Mobile Pleno (Flutter + React Native)"},{"content":"Sobre a vagaA SumUp busca uma pessoa Gerente de Engenharia sênior para atuar presencialmente em São Paulo, São Paulo, Brasil.\nResponsabilidadesLiderar times de engenharia e apoiar a entrega de soluções de software.Orientar decisões técnicas em sistemas distribuídos, microservices e plataformas em nuvem.Colaborar com pessoas engenheiras e stakeholders para priorizar iniciativas e melhorar processos de entrega.RequisitosExperiência em liderança de engenharia em nível sênior.Vivência com arquitetura de microservices, containers, orquestração e práticas de CI/CD.Conhecimento em tecnologias como Kotlin, Golang, Python ou Elixir.Experiência com AWS e mensageria, incluindo SNS/SQS, RabbitMQ ou Kafka.Familiaridade com bancos de dados e cache, como PostgreSQL, DynamoDB e Redis.Local de trabalhoAtuação presencial em São Paulo, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/7i6jl1tgno0w4o1f-sumup-gerente-de-engenharia/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA SumUp busca uma pessoa Gerente de Engenharia sênior para atuar presencialmente em São Paulo, São Paulo, Brasil.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLiderar times de engenharia e apoiar a entrega de soluções de software.\u003c/li\u003e\u003cli\u003eOrientar decisões técnicas em sistemas distribuídos, microservices e plataformas em nuvem.\u003c/li\u003e\u003cli\u003eColaborar com pessoas engenheiras e stakeholders para priorizar iniciativas e melhorar processos de entrega.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em liderança de engenharia em nível sênior.\u003c/li\u003e\u003cli\u003eVivência com arquitetura de microservices, containers, orquestração e práticas de CI/CD.\u003c/li\u003e\u003cli\u003eConhecimento em tecnologias como Kotlin, Golang, Python ou Elixir.\u003c/li\u003e\u003cli\u003eExperiência com AWS e mensageria, incluindo SNS/SQS, RabbitMQ ou Kafka.\u003c/li\u003e\u003cli\u003eFamiliaridade com bancos de dados e cache, como PostgreSQL, DynamoDB e Redis.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eAtuação presencial em São Paulo, São Paulo, Brasil.\u003c/p\u003e","title":"Gerente de Engenharia"},{"content":"Sobre a vagaA Getnet busca uma pessoa Líder Técnico Java/PIX para atuação híbrida. A vaga é de nível pleno e aceita candidatura a partir de São Paulo, Espanha, Portugal, Brasil, México, Chile, Argentina ou Uruguai.\nResponsabilidadesLiderar tecnicamente iniciativas relacionadas a Java e PIX.Apoiar decisões de arquitetura, integração e evolução de APIs.Colaborar com times de engenharia, produto e demais áreas técnicas.Acompanhar entregas usando ferramentas de gestão e documentação.Requisitos e tecnologiasExperiência com Java, Kotlin e Spring Framework.Conhecimento em APIs, Swagger e API Gateway.Vivência com JavaScript, TypeScript, Node.js ou Python.Experiência com AWS ou Azure.Conhecimento em MongoDB e RabbitMQ.Uso de Git, Jenkins e Terraform.Familiaridade com Jira e Confluence.Benefícios e recursosAcesso a plataformas de aprendizado como LinkedIn Learning e O'Reilly, conforme informado na vaga. ","permalink":"https://kotlin.dev.br/vagas/3hql66ye594fj8m4-getnet-lider-tecnico-java-pix/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Getnet busca uma pessoa \u003cstrong\u003eLíder Técnico Java/PIX\u003c/strong\u003e para atuação híbrida. A vaga é de nível pleno e aceita candidatura a partir de São Paulo, Espanha, Portugal, Brasil, México, Chile, Argentina ou Uruguai.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLiderar tecnicamente iniciativas relacionadas a Java e PIX.\u003c/li\u003e\u003cli\u003eApoiar decisões de arquitetura, integração e evolução de APIs.\u003c/li\u003e\u003cli\u003eColaborar com times de engenharia, produto e demais áreas técnicas.\u003c/li\u003e\u003cli\u003eAcompanhar entregas usando ferramentas de gestão e documentação.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com \u003cstrong\u003eJava\u003c/strong\u003e, \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eSpring Framework\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em APIs, Swagger e API Gateway.\u003c/li\u003e\u003cli\u003eVivência com JavaScript, TypeScript, Node.js ou Python.\u003c/li\u003e\u003cli\u003eExperiência com AWS ou Azure.\u003c/li\u003e\u003cli\u003eConhecimento em MongoDB e RabbitMQ.\u003c/li\u003e\u003cli\u003eUso de Git, Jenkins e Terraform.\u003c/li\u003e\u003cli\u003eFamiliaridade com Jira e Confluence.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eBenefícios e recursos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAcesso a plataformas de aprendizado como LinkedIn Learning e O'Reilly, conforme informado na vaga.\u003c/li\u003e\u003c/ul\u003e","title":"Líder Técnico Java/PIX"},{"content":"Sobre a vagaA Exadel busca um Middle Software Engineer com sólida experiência em Java e Quarkus para desenvolver soluções robustas na AWS. Você atuará em um ambiente remoto, trabalhando com tecnologias modernas de nuvem e infraestrutura.\nResponsabilidadesDesenvolver e manter aplicações backend com Java e QuarkusImplementar soluções na AWS utilizando serviços como Lambda, ECS, API Gateway e SQSTrabalhar com infraestrutura como código usando Terraform e CloudFormationIntegrar sistemas com Kafka, RabbitMQ e outros Message BrokersGerenciar bancos de dados PostgreSQL e MySQLContainerizar aplicações com Docker e orquestrar com KubernetesRequisitos3+ anos de experiência em desenvolvimento JavaExperiência com Quarkus e AWSConhecimento em Docker e KubernetesFamiliaridade com padrões de microserviçosExperiência com bancos de dados relacionais (PostgreSQL, MySQL)DiferenciaisExperiência com KotlinConhecimento em Python e GolangExperiência com AnsibleCertificações AWS ","permalink":"https://kotlin.dev.br/vagas/q71yc4j1bk8aq2p6-exadel-middle-software-engineer-java-quarkus-aws/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Exadel busca um Middle Software Engineer com sólida experiência em Java e Quarkus para desenvolver soluções robustas na AWS. Você atuará em um ambiente remoto, trabalhando com tecnologias modernas de nuvem e infraestrutura.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações backend com Java e Quarkus\u003c/li\u003e\u003cli\u003eImplementar soluções na AWS utilizando serviços como Lambda, ECS, API Gateway e SQS\u003c/li\u003e\u003cli\u003eTrabalhar com infraestrutura como código usando Terraform e CloudFormation\u003c/li\u003e\u003cli\u003eIntegrar sistemas com Kafka, RabbitMQ e outros Message Brokers\u003c/li\u003e\u003cli\u003eGerenciar bancos de dados PostgreSQL e MySQL\u003c/li\u003e\u003cli\u003eContainerizar aplicações com Docker e orquestrar com Kubernetes\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003e3+ anos de experiência em desenvolvimento Java\u003c/li\u003e\u003cli\u003eExperiência com Quarkus e AWS\u003c/li\u003e\u003cli\u003eConhecimento em Docker e Kubernetes\u003c/li\u003e\u003cli\u003eFamiliaridade com padrões de microserviços\u003c/li\u003e\u003cli\u003eExperiência com bancos de dados relacionais (PostgreSQL, MySQL)\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin\u003c/li\u003e\u003cli\u003eConhecimento em Python e Golang\u003c/li\u003e\u003cli\u003eExperiência com Ansible\u003c/li\u003e\u003cli\u003eCertificações AWS\u003c/li\u003e\u003c/ul\u003e","title":"Middle Software Engineer (Java + Quarkus + AWS)"},{"content":"Sobre a vagaBuscamos uma pessoa desenvolvedora sênior backend para integrar o time de Investments Engineering do C6 Bank. Você trabalhará com tecnologias modernas e escaláveis em ambiente colaborativo e inovador.\nResponsabilidadesDesenvolver e manter soluções backend robustas em Kotlin e JavaArquitetar serviços utilizando Spring Boot e padrões enterpriseOtimizar performance de aplicações e bancos de dadosColaborar com times multidisciplinares em projetos de investimentosImplementar práticas de DevOps e CI/CDParticipar de code reviews e mentoria técnicaRequisitosExperiência sênior em Kotlin e/ou JavaProficiência com Spring Boot e Spring FrameworkConhecimento sólido em PostgreSQL e MongoDBExperiência com sistemas de mensageria (Kafka, SQS, SNS)Familiaridade com AWS (S3, RDS, infraestrutura cloud)Conhecimento de Kubernetes e containerizaçãoExperiência com monitoramento (Grafana, AppDynamics)DiferenciaisExperiência prévia em setor financeiro ou fintechsConhecimento avançado em arquitetura de microsserviçosContribuições a projetos open source ","permalink":"https://kotlin.dev.br/vagas/xk753ys0qusx6i5m-c6-bank-pessoa-desenvolvedora-senior-backend-kotlin-java/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos uma pessoa desenvolvedora sênior backend para integrar o time de Investments Engineering do C6 Bank. Você trabalhará com tecnologias modernas e escaláveis em ambiente colaborativo e inovador.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter soluções backend robustas em Kotlin e Java\u003c/li\u003e\u003cli\u003eArquitetar serviços utilizando Spring Boot e padrões enterprise\u003c/li\u003e\u003cli\u003eOtimizar performance de aplicações e bancos de dados\u003c/li\u003e\u003cli\u003eColaborar com times multidisciplinares em projetos de investimentos\u003c/li\u003e\u003cli\u003eImplementar práticas de DevOps e CI/CD\u003c/li\u003e\u003cli\u003eParticipar de code reviews e mentoria técnica\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em Kotlin e/ou Java\u003c/li\u003e\u003cli\u003eProficiência com Spring Boot e Spring Framework\u003c/li\u003e\u003cli\u003eConhecimento sólido em PostgreSQL e MongoDB\u003c/li\u003e\u003cli\u003eExperiência com sistemas de mensageria (Kafka, SQS, SNS)\u003c/li\u003e\u003cli\u003eFamiliaridade com AWS (S3, RDS, infraestrutura cloud)\u003c/li\u003e\u003cli\u003eConhecimento de Kubernetes e containerização\u003c/li\u003e\u003cli\u003eExperiência com monitoramento (Grafana, AppDynamics)\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência prévia em setor financeiro ou fintechs\u003c/li\u003e\u003cli\u003eConhecimento avançado em arquitetura de microsserviços\u003c/li\u003e\u003cli\u003eContribuições a projetos open source\u003c/li\u003e\u003c/ul\u003e","title":"Pessoa Desenvolvedora Sênior Backend Kotlin/Java"},{"content":"Sobre a vagaProcuramos um QA Automation Engineer mid-level para integrar o KDS Squad na Qu. Você será responsável por desenvolver e manter testes automatizados de alta qualidade utilizando tecnologias modernas como Kotlin, Java, Selenium, Playwright e Appium.\nResponsabilidadesDesenvolver e manter suites de testes automatizadosImplementar testes de API REST com qualidade e cobertura adequadaTrabalhar com automação web (Selenium, Playwright) e mobile (Appium)Integrar testes com pipelines CI/CD utilizando Azure DevOpsColaborar com equipes de desenvolvimento para garantir qualidade do produtoUtilizar Git para controle de versão e Docker para ambientes de testeRequisitosExperiência comprovada com automação de testesConhecimento sólido em Java e/ou KotlinExperiência com Selenium, Playwright ou AppiumFamiliaridade com TestNG e MavenConhecimento de REST API TestingExperiência com Azure DevOps, Docker e CI/CDProficiência com GitInglês fluente para comunicação com equipe internacional ","permalink":"https://kotlin.dev.br/vagas/j94vqy3wtj2p6oy0-qu-qa-automation-engineer-kds-squad/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eProcuramos um QA Automation Engineer mid-level para integrar o KDS Squad na Qu. Você será responsável por desenvolver e manter testes automatizados de alta qualidade utilizando tecnologias modernas como Kotlin, Java, Selenium, Playwright e Appium.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter suites de testes automatizados\u003c/li\u003e\u003cli\u003eImplementar testes de API REST com qualidade e cobertura adequada\u003c/li\u003e\u003cli\u003eTrabalhar com automação web (Selenium, Playwright) e mobile (Appium)\u003c/li\u003e\u003cli\u003eIntegrar testes com pipelines CI/CD utilizando Azure DevOps\u003c/li\u003e\u003cli\u003eColaborar com equipes de desenvolvimento para garantir qualidade do produto\u003c/li\u003e\u003cli\u003eUtilizar Git para controle de versão e Docker para ambientes de teste\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência comprovada com automação de testes\u003c/li\u003e\u003cli\u003eConhecimento sólido em Java e/ou Kotlin\u003c/li\u003e\u003cli\u003eExperiência com Selenium, Playwright ou Appium\u003c/li\u003e\u003cli\u003eFamiliaridade com TestNG e Maven\u003c/li\u003e\u003cli\u003eConhecimento de REST API Testing\u003c/li\u003e\u003cli\u003eExperiência com Azure DevOps, Docker e CI/CD\u003c/li\u003e\u003cli\u003eProficiência com Git\u003c/li\u003e\u003cli\u003eInglês fluente para comunicação com equipe internacional\u003c/li\u003e\u003c/ul\u003e","title":"QA Automation Engineer – KDS Squad"},{"content":"Modularização Android é uma daquelas decisões que parecem arquitetura pura, mas rapidamente viram assunto de produto. Um app Kotlin pequeno pode viver bem em um único módulo :app. Conforme o time cresce, as telas aumentam, o design system amadurece, os testes ficam mais caros e o CI passa a demorar demais, separar tudo em módulos Gradle começa a pagar a conta.\nO problema é que modularizar cedo demais também cobra juros. Criar vinte módulos antes de entender as fronteiras reais do app aumenta boilerplate, dificulta navegação no código e cria dependências artificiais. Em 2026, a melhor abordagem para apps Android com Kotlin e Jetpack Compose é incremental: extrair módulos quando eles reduzem acoplamento, aceleram feedback ou deixam uma feature mais testável.\nEste guia mostra um caminho prático para modularizar sem transformar o projeto em um labirinto. Se você ainda está montando a base, leia também Kotlin para Android, Clean Architecture em Kotlin e Gradle Build Cache em projetos Kotlin.\nQuando modularizar um app Android A pergunta boa não é \u0026ldquo;quantos módulos um app moderno precisa ter?\u0026rdquo;. A pergunta é: qual dor concreta o módulo resolve?\nModularização costuma fazer sentido quando:\no build do app completo está lento demais para feedback diário; uma feature tem regras, telas e testes que mudam juntas; o design system precisa ser reutilizado por várias áreas; o time quer rodar testes de um domínio sem compilar o app inteiro; dependências de infraestrutura estão vazando para camadas que deveriam ser simples; múltiplos squads mexem no mesmo :app e geram conflitos frequentes; o app precisa compartilhar lógica com KMP, Wear, TV ou backend auxiliar. Se o único motivo é \u0026ldquo;arquitetura bonita\u0026rdquo;, espere. Um módulo cria uma API pública interna. APIs públicas exigem nomes melhores, documentação mínima e disciplina de dependências.\nUm desenho inicial saudável Um ponto de partida comum para Android Kotlin é separar o app em módulos de entrada, módulos compartilhados e módulos de feature:\n:app :core:designsystem :core:model :core:network :core:database :core:analytics :feature:login :feature:home :feature:profile :feature:checkout O módulo :app deve ser fino. Ele inicializa aplicação, DI, tema global e navegação de alto nível. Ele não deveria concentrar regra de negócio, componentes visuais genéricos nem clients HTTP.\nMódulos :core:* carregam capacidades compartilhadas. O :core:model pode conter modelos de domínio estáveis. O :core:designsystem reúne componentes Compose reutilizáveis, tokens, temas e previews. O :core:network sabe falar com APIs. O :core:database encapsula Room ou SQLDelight. O :core:analytics padroniza eventos.\nMódulos :feature:* representam fluxos de produto. Uma feature pode depender de core, mas não deveria depender diretamente de outra feature sem um contrato claro.\nEvite o grafo emaranhado O maior risco da modularização é trocar um :app gigante por um grafo onde tudo depende de tudo. Para evitar isso, defina regras simples:\n:app -\u0026gt; :feature:* -\u0026gt; :core:* :feature:* -\u0026gt; :core:model :feature:* -\u0026gt; :core:designsystem :core:network -\u0026gt; :core:model :core:database -\u0026gt; :core:model Evite dependências laterais como :feature:checkout dependendo de :feature:profile. Se checkout precisa mostrar dados de perfil, crie um contrato em :core:model, :core:session ou um módulo de API menor. Dependência lateral parece prática no começo, mas vira ciclo conceitual rapidamente.\nUma regra útil é: feature depende de contrato, não de implementação de outra feature. Isso preserva autonomia e facilita testes.\nConvention plugins para não repetir Gradle Sem convention plugins, cada módulo novo vira um arquivo build.gradle.kts copiado e levemente diferente. Um módulo esquece jvmTarget, outro esquece Compose Compiler, outro usa dependências de teste desatualizadas. Isso derruba consistência e atrapalha cache.\nCrie plugins internos no build-logic para padrões recorrentes:\n// build-logic/src/main/kotlin/AndroidFeatureConventionPlugin.kt class AndroidFeatureConventionPlugin : Plugin\u0026lt;Project\u0026gt; { override fun apply(target: Project) = with(target) { pluginManager.apply(\u0026#34;com.android.library\u0026#34;) pluginManager.apply(\u0026#34;org.jetbrains.kotlin.android\u0026#34;) pluginManager.apply(\u0026#34;org.jetbrains.kotlin.plugin.compose\u0026#34;) extensions.configure\u0026lt;LibraryExtension\u0026gt; { namespace = \u0026#34;br.com.exemplo.${project.name.replace(\u0026#39;-\u0026#39;, \u0026#39;.\u0026#39;)}\u0026#34; compileSdk = 36 defaultConfig { minSdk = 26 testInstrumentationRunner = \u0026#34;androidx.test.runner.AndroidJUnitRunner\u0026#34; } } } } Depois, nos módulos de feature:\nplugins { id(\u0026#34;exemplo.android.feature\u0026#34;) } dependencies { implementation(projects.core.model) implementation(projects.core.designsystem) } Essa padronização combina com Kotlin com Gradle e Version Catalogs em Kotlin. O objetivo é que criar um módulo seja barato, mas consistente.\nCompose ajuda, mas não elimina fronteiras Jetpack Compose facilita dividir UI em componentes menores, mas componente não é a mesma coisa que módulo. Um botão, card ou skeleton loader pertence ao :core:designsystem. Uma tela de login pertence ao :feature:login. Um fluxo de onboarding talvez vire :feature:onboarding.\nUse previews para manter o design system saudável:\n@Preview(showBackground = true) @Composable private fun PrimaryButtonPreview() { AppTheme { PrimaryButton( text = \u0026#34;Continuar\u0026#34;, onClick = {} ) } } Quando o design system fica em módulo próprio, previews, testes de screenshot e documentação visual podem evoluir sem recompilar todas as features. Se você já está nessa fase, o artigo de testes de screenshot no Compose é o próximo passo natural.\nInjeção de dependência entre módulos Hilt, Koin ou DI manual funcionam em projetos modularizados, mas a regra é a mesma: módulos de feature não deveriam conhecer detalhes desnecessários.\nCom Hilt, mantenha bindings próximos da implementação e exponha contratos estáveis:\ninterface ProfileRepository { suspend fun currentProfile(): Profile } @Module @InstallIn(SingletonComponent::class) abstract class ProfileDataModule { @Binds abstract fun bindProfileRepository( impl: NetworkProfileRepository ): ProfileRepository } Se uma feature só precisa de ProfileRepository, ela não precisa saber se os dados vêm de Retrofit, Ktor Client, Room ou DataStore. Para aprofundar a escolha entre ferramentas, veja Hilt no Android com Kotlin e Koin ou Hilt em Kotlin.\nTestes ficam mais baratos quando a fronteira é boa Um benefício real da modularização é rodar testes menores. Se :feature:checkout concentra UI, view models e casos de uso daquele fluxo, o CI pode executar:\n./gradlew :feature:checkout:testDebugUnitTest ./gradlew :feature:checkout:lintDebug Isso reduz feedback em pull requests. Mas só funciona se as dependências forem limpas. Se o módulo de checkout depende de metade do app, o teste continua pesado.\nPara módulos de domínio, prefira testes JVM simples com JUnit, MockK e coroutines test. Para módulos de UI, combine testes de view model, previews revisáveis e screenshot tests quando o custo se justificar. O guia de testes Android com Compose e Maestro ajuda a decidir onde entra cada camada.\nCI/CD por módulos afetados Depois que o grafo está estável, vale evoluir o pipeline. O primeiro passo é continuar rodando ./gradlew check em main. Em pull requests, você pode detectar arquivos alterados e priorizar módulos impactados.\nExemplo simplificado:\n./gradlew :feature:home:check :core:designsystem:check Não pule validação global cedo demais. Em times pequenos, um pipeline completo pode ser mais simples e seguro. Em monorepos grandes, a seleção por módulos afetados economiza muito tempo, especialmente quando combinada com Gradle build cache e configuration cache. O guia de CI/CD para Kotlin cobre essa base.\nSinais de overengineering Modularização deve deixar o projeto mais fácil de mudar. Se ela está piorando tudo, os sinais aparecem:\ncriar uma tela simples exige mexer em cinco módulos; nomes de módulos refletem camadas abstratas demais, não produto real; quase todo módulo depende de :core:common com centenas de utilitários; há ciclos ou dependências indiretas difíceis de explicar; o tempo de configuração do Gradle aumentou mais do que o tempo economizado; a navegação entre arquivos ficou mais lenta para o time; testes continuam lentos porque os módulos não têm fronteiras reais. Nesses casos, simplifique. Junte módulos pequenos demais, divida common por responsabilidade e documente as regras de dependência no README técnico.\nChecklist prático Antes de extrair um módulo, responda:\nQual dor concreta esse módulo resolve? Quem pode depender dele? Ele expõe contrato ou implementação? Quais dependências ficam proibidas? Quais testes devem rodar isoladamente? O módulo melhora ou piora o tempo de build? O nome descreve produto/capacidade real? Se as respostas forem vagas, talvez ainda seja cedo.\nPerguntas frequentes Todo app Android Kotlin precisa ser modularizado? Não. Apps pequenos podem viver bem em um único módulo por bastante tempo. Modularize quando houver dor real de build, testes, organização, reuso ou colaboração.\nDevo separar por camada ou por feature? Para apps de produto, módulos por feature costumam ser mais úteis. Camadas compartilhadas entram em core ou módulos de domínio. Separar apenas por data, domain e presentation no app inteiro pode criar acoplamento transversal e dificultar ownership.\nModularização melhora performance do app? Indiretamente. Ela melhora build, testes e organização. Performance de runtime depende de código, inicialização, tamanho de APK/AAB, baseline profiles e uso correto de APIs Android. Modularização ajuda a controlar isso, mas não substitui medição.\nDynamic Feature Modules ainda valem a pena? Valem quando você realmente precisa entregar partes do app sob demanda para reduzir download inicial ou separar fluxos raros. Não use dynamic feature apenas para organizar código; módulos Gradle normais já resolvem organização sem complexidade extra de entrega.\nQuantos módulos são demais? Não existe número universal. O limite aparece quando o overhead de navegação, configuração e dependências supera o ganho de isolamento. Comece com poucos módulos de alto valor e extraia novos conforme o app pedir.\nConclusão Modularização Android com Kotlin é uma ferramenta de escala, não um troféu arquitetural. Comece pelo problema: build lento, feature grande demais, design system compartilhado, testes caros ou fronteiras confusas. Extraia módulos pequenos, com contratos claros, Gradle padronizado e dependências previsíveis.\nO melhor projeto modularizado é aquele em que uma pessoa consegue mudar uma feature, rodar testes relevantes, entender impactos e abrir pull request sem carregar o app inteiro nas costas. Em 2026, Kotlin, Compose e Gradle já dão a base técnica. O diferencial é usar essa base com pragmatismo.\n","permalink":"https://kotlin.dev.br/blog/modularizacao-android-kotlin-compose-2026/","summary":"\u003cp\u003eModularização Android é uma daquelas decisões que parecem arquitetura pura, mas rapidamente viram assunto de produto. Um app Kotlin pequeno pode viver bem em um único módulo \u003ccode\u003e:app\u003c/code\u003e. Conforme o time cresce, as telas aumentam, o design system amadurece, os testes ficam mais caros e o CI passa a demorar demais, separar tudo em módulos Gradle começa a pagar a conta.\u003c/p\u003e\n\u003cp\u003eO problema é que modularizar cedo demais também cobra juros. Criar vinte módulos antes de entender as fronteiras reais do app aumenta boilerplate, dificulta navegação no código e cria dependências artificiais. Em 2026, a melhor abordagem para apps Android com Kotlin e Jetpack Compose é incremental: extrair módulos quando eles reduzem acoplamento, aceleram feedback ou deixam uma feature mais testável.\u003c/p\u003e","title":"Modularização Android com Kotlin e Compose em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA Starbridge busca uma pessoa Engenheira de IA sênior para atuação remota na Europa ou América do Sul.\nA posição envolve trabalho com Kotlin, Python, modelos de linguagem e ferramentas modernas para desenvolvimento, orquestração e avaliação de aplicações de IA.\nTecnologiasKotlin e PythonOpenAI, Anthropic e GeminiLangGraph, LiteLLM, Agent Client Protocol e KoogMLflow, DVC e Weights \u0026amp; BiasesParallel.aiRequisitosExperiência sênior em engenharia de software ou engenharia de IA.Vivência com LLMs, agentes de IA e integrações com provedores de modelos.Conhecimento prático em Python e interesse ou experiência com Kotlin.Experiência com ferramentas de experimentação, versionamento e observabilidade de modelos.Capacidade de atuar de forma remota com times distribuídos.Local de trabalhoVaga remota para profissionais localizados na Europa ou América do Sul.\n","permalink":"https://kotlin.dev.br/vagas/dw7lwb0b0gwyfaz4-starbridge-engenheiro-a-de-ia-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Starbridge busca uma pessoa Engenheira de IA sênior para atuação remota na Europa ou América do Sul.\u003c/p\u003e\u003cp\u003eA posição envolve trabalho com Kotlin, Python, modelos de linguagem e ferramentas modernas para desenvolvimento, orquestração e avaliação de aplicações de IA.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Python\u003c/li\u003e\u003cli\u003eOpenAI, Anthropic e Gemini\u003c/li\u003e\u003cli\u003eLangGraph, LiteLLM, Agent Client Protocol e Koog\u003c/li\u003e\u003cli\u003eMLflow, DVC e Weights \u0026amp; Biases\u003c/li\u003e\u003cli\u003eParallel.ai\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software ou engenharia de IA.\u003c/li\u003e\u003cli\u003eVivência com LLMs, agentes de IA e integrações com provedores de modelos.\u003c/li\u003e\u003cli\u003eConhecimento prático em Python e interesse ou experiência com Kotlin.\u003c/li\u003e\u003cli\u003eExperiência com ferramentas de experimentação, versionamento e observabilidade de modelos.\u003c/li\u003e\u003cli\u003eCapacidade de atuar de forma remota com times distribuídos.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais localizados na Europa ou América do Sul.\u003c/p\u003e","title":"Engenheiro(a) de IA Sênior"},{"content":"Sobre a vagaO iFood busca uma pessoa Staff Backend Software Engineer para atuar na área de Logística, em posição sênior e presencial no Brasil.\nStack e contexto técnicoKotlin, Java e Rust para desenvolvimento backend.Kafka, SQS e SNS para mensageria e sistemas distribuídos.AWS, Kubernetes e Docker para infraestrutura e execução de serviços.Linux e Infrastructure as Code no ambiente de engenharia.RequisitosExperiência sênior em engenharia de software backend.Vivência com sistemas distribuídos, mensageria e serviços em nuvem.Capacidade de atuar em nível Staff, apoiando decisões técnicas e evolução de arquitetura.Experiência prática com parte da stack informada, especialmente Kotlin, Java, Kafka, AWS, Kubernetes ou Docker. ","permalink":"https://kotlin.dev.br/vagas/tstqvr2q0t1y5pdo-ifood-engenheiro-a-de-software-backend-staff-logistica/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa Staff Backend Software Engineer para atuar na área de Logística, em posição sênior e presencial no Brasil.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java e Rust para desenvolvimento backend.\u003c/li\u003e\u003cli\u003eKafka, SQS e SNS para mensageria e sistemas distribuídos.\u003c/li\u003e\u003cli\u003eAWS, Kubernetes e Docker para infraestrutura e execução de serviços.\u003c/li\u003e\u003cli\u003eLinux e Infrastructure as Code no ambiente de engenharia.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software backend.\u003c/li\u003e\u003cli\u003eVivência com sistemas distribuídos, mensageria e serviços em nuvem.\u003c/li\u003e\u003cli\u003eCapacidade de atuar em nível Staff, apoiando decisões técnicas e evolução de arquitetura.\u003c/li\u003e\u003cli\u003eExperiência prática com parte da stack informada, especialmente Kotlin, Java, Kafka, AWS, Kubernetes ou Docker.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Backend Staff - Logística"},{"content":"Sobre a vagaO C6 Bank busca uma Pessoa Desenvolvedora Backend Especialista Java/Kotlin para atuar na área de Investments Engineering.\nRequisitos e tecnologiasExperiência sênior em desenvolvimento Backend com Java e Kotlin.Conhecimento em Spring Boot.Experiência com bancos NoSQL.Vivência com CI/CD e Git.Conhecimento em ambientes Cloud.Local de trabalhoVaga presencial em São Paulo, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/512s2tiajx6mtidi-c6-bank-pessoa-desenvolvedora-backend-especialista-java-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma Pessoa Desenvolvedora Backend Especialista Java/Kotlin para atuar na área de Investments Engineering.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Backend com \u003cstrong\u003eJava\u003c/strong\u003e e \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eSpring Boot\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com bancos \u003cstrong\u003eNoSQL\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com \u003cstrong\u003eCI/CD\u003c/strong\u003e e \u003cstrong\u003eGit\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em ambientes \u003cstrong\u003eCloud\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em São Paulo, São Paulo, Brasil.\u003c/p\u003e","title":"Pessoa Desenvolvedora Backend Especialista Java/Kotlin"},{"content":"Sobre a vagaA Zup Innovation busca uma Pessoa Desenvolvedora Backend Java de nível pleno para atuação remota a partir de São Paulo.\nTecnologiasKotlinJavaGoAWSKubernetesTerraformCI/CDGitRequisitosExperiência em desenvolvimento backend com Java.Conhecimento em Kotlin e ambientes cloud com AWS.Vivência com Kubernetes, Terraform, pipelines de CI/CD e Git.Disponibilidade para trabalho remoto. ","permalink":"https://kotlin.dev.br/vagas/pg9tockuffascrdo-zup-innovation-pessoa-desenvolvedora-backend-java/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Zup Innovation busca uma Pessoa Desenvolvedora Backend Java de nível pleno para atuação remota a partir de São Paulo.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eGo\u003c/li\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eKubernetes\u003c/li\u003e\u003cli\u003eTerraform\u003c/li\u003e\u003cli\u003eCI/CD\u003c/li\u003e\u003cli\u003eGit\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento backend com Java.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin e ambientes cloud com AWS.\u003c/li\u003e\u003cli\u003eVivência com Kubernetes, Terraform, pipelines de CI/CD e Git.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho remoto.\u003c/li\u003e\u003c/ul\u003e","title":"Pessoa Desenvolvedora Backend Java"},{"content":"Camera em app Android parece simples até o primeiro fluxo real: pedir permissão no momento certo, abrir o preview sem vazar Activity, capturar uma foto com rotação correta, pausar quando a tela sai de foco, analisar frames sem travar a UI e explicar para QA por que o emulador não reproduz o bug do aparelho físico. Em 2026, a forma mais segura de começar é combinar CameraX com Kotlin e Jetpack Compose.\nCameraX é a camada Jetpack que reduz a diferença entre fabricantes, versões de Android e APIs antigas de câmera. Compose, por outro lado, não substitui tudo que existe no Android View system. O padrão prático é usar Compose para estado e layout, e embutir PreviewView dentro de AndroidView para renderizar o preview da câmera.\nEste guia mostra uma arquitetura enxuta para app Android Kotlin com câmera: dependências, permissão, preview, captura de foto, análise de imagem, lifecycle, tratamento de erro e testes. Se você está montando um app maior, conecte este fluxo com permissões no Android com Kotlin, Android offline-first, segurança de dados locais e testes Android com Compose e Maestro.\nQuando usar CameraX Use CameraX quando o app precisa controlar câmera dentro da própria experiência: scanner de documento, leitura de QR Code, captura de recibo, validação de identidade, foto de perfil guiada, medição visual, inventário, vistoria, registro de entrega ou análise de imagem em tempo real.\nSe o requisito é só “o usuário escolhe ou tira uma foto”, avalie primeiro ActivityResultContracts.TakePicture, Photo Picker ou um intent externo. Menos código costuma significar menos risco. CameraX vale a pena quando o preview, o enquadramento, a análise ou a experiência guiada fazem parte do produto.\nDependências base Em um módulo Android com Gradle Kotlin DSL, uma base comum fica assim:\ndependencies { implementation(\u0026#34;androidx.camera:camera-core:1.4.1\u0026#34;) implementation(\u0026#34;androidx.camera:camera-camera2:1.4.1\u0026#34;) implementation(\u0026#34;androidx.camera:camera-lifecycle:1.4.1\u0026#34;) implementation(\u0026#34;androidx.camera:camera-view:1.4.1\u0026#34;) implementation(\u0026#34;androidx.activity:activity-compose:1.10.1\u0026#34;) implementation(\u0026#34;androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7\u0026#34;) } Use versões alinhadas ao seu Android Gradle Plugin e ao Compose BOM do projeto. Em times grandes, prefira centralizar essas versões em Version Catalog com Gradle Kotlin DSL para evitar cada módulo puxar uma versão diferente de CameraX.\nNo AndroidManifest.xml, declare apenas o necessário:\n\u0026lt;uses-permission android:name=\u0026#34;android.permission.CAMERA\u0026#34; /\u0026gt; Não peça microfone, localização ou armazenamento se o fluxo não usa esses recursos. Permissão extra piora confiança, revisão de loja e manutenção.\nPermissão antes do preview Não inicialize CameraX antes de saber que a permissão foi concedida. Em Compose, o fluxo costuma ficar em três estados: explicação, pedido do sistema e câmera ativa.\n@Composable fun CameraPermissionGate( onPermissionGranted: @Composable () -\u0026gt; Unit, ) { val context = LocalContext.current var granted by remember { mutableStateOf( ContextCompat.checkSelfPermission( context, Manifest.permission.CAMERA, ) == PackageManager.PERMISSION_GRANTED, ) } val launcher = rememberLauncherForActivityResult( ActivityResultContracts.RequestPermission(), ) { result -\u0026gt; granted = result } if (granted) { onPermissionGranted() } else { Column(Modifier.padding(24.dp)) { Text(\u0026#34;Precisamos da câmera para enquadrar o documento antes da captura.\u0026#34;) Button(onClick = { launcher.launch(Manifest.permission.CAMERA) }) { Text(\u0026#34;Permitir câmera\u0026#34;) } } } } A mensagem deve explicar a tarefa atual, não a tecnologia. “Precisamos da câmera para enquadrar o documento” é melhor que “o app requer permissão de câmera”. Para recusa permanente, mostre uma alternativa e um caminho para configurações, sem loop infinito de popup.\nPreviewView dentro de Compose CameraX ainda entrega o preview por PreviewView. Em Compose, use AndroidView e mantenha a inicialização em uma função separada. Isso evita transformar o composable em um bloco gigante de side effects.\n@Composable fun CameraPreview( modifier: Modifier = Modifier, onImageCaptureReady: (ImageCapture) -\u0026gt; Unit, ) { val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current AndroidView( modifier = modifier.fillMaxSize(), factory = { ctx -\u0026gt; PreviewView(ctx).also { previewView -\u0026gt; val cameraProviderFuture = ProcessCameraProvider.getInstance(ctx) cameraProviderFuture.addListener({ val cameraProvider = cameraProviderFuture.get() val preview = Preview.Builder().build().also { it.setSurfaceProvider(previewView.surfaceProvider) } val imageCapture = ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build() cameraProvider.unbindAll() cameraProvider.bindToLifecycle( lifecycleOwner, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageCapture, ) onImageCaptureReady(imageCapture) }, ContextCompat.getMainExecutor(ctx)) } }, ) } O ponto crítico é o lifecycle: bindToLifecycle faz CameraX pausar e retomar junto com a tela. Sem isso, você aumenta o risco de câmera presa, consumo de bateria e crash ao navegar.\nCapture foto sem travar a UI Guarde o ImageCapture em estado e dispare a captura a partir de um botão Compose. Salve em arquivo interno ou cache quando a imagem ainda não deve ir para a galeria.\n@Composable fun CameraScreen() { val context = LocalContext.current var imageCapture by remember { mutableStateOf\u0026lt;ImageCapture?\u0026gt;(null) } var saving by remember { mutableStateOf(false) } Box(Modifier.fillMaxSize()) { CameraPreview(onImageCaptureReady = { imageCapture = it }) Button( enabled = imageCapture != null \u0026amp;\u0026amp; !saving, onClick = { val capture = imageCapture ?: return@Button saving = true val file = File(context.cacheDir, \u0026#34;captura-${System.currentTimeMillis()}.jpg\u0026#34;) val output = ImageCapture.OutputFileOptions.Builder(file).build() capture.takePicture( output, ContextCompat.getMainExecutor(context), object : ImageCapture.OnImageSavedCallback { override fun onImageSaved(result: ImageCapture.OutputFileResults) { saving = false // envie file.absolutePath para o ViewModel ou fluxo seguinte } override fun onError(exception: ImageCaptureException) { saving = false // registre o erro e mostre uma mensagem recuperável } }, ) }, modifier = Modifier.align(Alignment.BottomCenter).padding(24.dp), ) { Text(if (saving) \u0026#34;Salvando...\u0026#34; else \u0026#34;Capturar\u0026#34;) } } } Em produção, mova a decisão de destino para uma camada própria. Foto de documento, selfie de identidade e imagem pública têm requisitos diferentes de retenção, criptografia, upload e exclusão.\nAnálise de imagem em tempo real Para QR Code, OCR, ML Kit ou validação de enquadramento, adicione ImageAnalysis. O erro comum é analisar todo frame como se CPU fosse infinita. Use backpressure e libere a imagem sempre.\nval analysis = ImageAnalysis.Builder() .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build() analysis.setAnalyzer(cameraExecutor) { imageProxy -\u0026gt; try { val rotation = imageProxy.imageInfo.rotationDegrees // converta ou envie para o analisador necessário } finally { imageProxy.close() } } Nunca esqueça imageProxy.close(). Um analyzer que não fecha frames rapidamente congela o pipeline da câmera. Para processamento pesado, use um executor dedicado, limite frequência e exponha resultado para a UI via StateFlow.\nEstado de tela e erros Evite espalhar Toast e flags soltas pelo composable. Um ViewModel pode modelar estados como:\ndata class CameraUiState( val permissionGranted: Boolean = false, val cameraReady: Boolean = false, val saving: Boolean = false, val lastImagePath: String? = null, val errorMessage: String? = null, ) Isso facilita testes e deixa claro o que a tela deve renderizar. Também ajuda a integrar o fluxo com upload offline-first, retries, telemetria, Crashlytics e analytics.\nCuidados de produção Antes de publicar um fluxo com câmera, revise esta lista:\npeça a permissão apenas depois de uma ação do usuário; mostre alternativa quando a permissão for negada; teste rotação, app em background, volta da tela e troca de câmera; trate aparelhos sem câmera traseira ou com câmera indisponível; não salve imagem sensível em diretório público por padrão; remova arquivos temporários que não serão usados; registre falhas com contexto, sem guardar foto em log; valide performance em aparelho intermediário, não só em emulador; se usar ML Kit, faça fallback quando o modelo não estiver disponível; documente quais imagens são enviadas para servidor e por quanto tempo ficam armazenadas. Esses detalhes importam para produto e carreira. Vagas Android que mencionam Kotlin, Compose, segurança, banco de dados local e testes geralmente esperam que a pessoa saiba discutir lifecycle e privacidade, não apenas abrir a câmera.\nComo testar CameraX Teste unitário não deve depender da câmera real. Separe o que é regra de produto do que é integração com hardware. Por exemplo: validação de estado, regra de habilitar botão, destino do arquivo, parser do resultado e mapeamento de erro podem rodar na JVM.\nPara UI, use Compose test em telas que não inicializam CameraX real ou injete um CameraController fake. Para fluxo completo, rode um teste manual guiado ou Maestro em aparelho físico quando o requisito envolver câmera. O emulador ajuda, mas não substitui diferença de fabricante, foco, rotação e performance.\nUm smoke test manual mínimo deve cobrir:\nprimeira abertura com permissão ainda não concedida; recusa simples; concessão de permissão; captura com rotação vertical e horizontal; navegação para fora e volta; app em background durante preview; arquivo temporário removido quando o fluxo é cancelado. Caminho recomendado Para um app novo, implemente nesta ordem:\ntela de explicação e permissão; preview com PreviewView e lifecycle; captura de foto para cache interno; estado em ViewModel; tratamento de erro e alternativa; análise de imagem se o produto realmente precisa; testes de regra e smoke test em aparelho físico. Essa sequência reduz risco. Você valida primeiro se a câmera abre de forma confiável e só depois adiciona ML, upload, edição ou OCR.\nConclusão CameraX com Compose e Kotlin é o caminho prático para câmera dentro do app Android moderno. Compose cuida da experiência e do estado; CameraX cuida da compatibilidade de hardware, preview, captura e análise. A qualidade vem de juntar os dois com lifecycle correto, permissão contextual, armazenamento cuidadoso e testes realistas.\nSe o seu objetivo é crescer como dev Android, trate câmera como um fluxo de produto completo. Ele cruza UI, permissões, lifecycle, performance, segurança local, testes e arquitetura — exatamente os temas que diferenciam um app demo de um app pronto para produção.\n","permalink":"https://kotlin.dev.br/blog/camerax-compose-kotlin-2026/","summary":"\u003cp\u003eCamera em app Android parece simples até o primeiro fluxo real: pedir permissão no momento certo, abrir o preview sem vazar \u003ccode\u003eActivity\u003c/code\u003e, capturar uma foto com rotação correta, pausar quando a tela sai de foco, analisar frames sem travar a UI e explicar para QA por que o emulador não reproduz o bug do aparelho físico. Em 2026, a forma mais segura de começar é combinar \u003cstrong\u003eCameraX com Kotlin e Jetpack Compose\u003c/strong\u003e.\u003c/p\u003e","title":"CameraX com Jetpack Compose e Kotlin em 2026 | Kotlin Brasil"},{"content":"Permissão no Android parece um detalhe de implementação até o produto perder conversão, receber avaliação ruim ou quebrar em uma atualização de sistema. Um app que pede localização antes de explicar o valor, solicita câmera sem contexto, insiste em notificação depois de uma recusa ou trata armazenamento como se ainda estivesse em 2018 transmite desconfiança. Em 2026, saber desenhar permissões no Android com Kotlin é parte de arquitetura, UX, segurança e carreira.\nO Android moderno tornou permissões mais granulares. Localização pode ser aproximada ou precisa. Fotos e vídeos podem ser selecionados sem acesso amplo à galeria. Notificações passaram a exigir consentimento explícito em versões recentes. Câmera, microfone, Bluetooth, sensores e serviços em primeiro plano têm regras próprias. Para times que usam Jetpack Compose, App Links, Android offline-first e testes Android com Kotlin, permissões precisam entrar no desenho da tela desde o início.\nEste guia mostra como pensar permissões em apps Android Kotlin: quando pedir, como explicar, como modelar estado, como evitar solicitações desnecessárias, quais casos exigem cuidado extra e como testar fluxos de aceite, recusa e configuração manual.\nO princípio: peça menos e peça melhor A melhor permissão é a que o app não precisa pedir. Antes de abrir o requestPermissionLauncher, responda três perguntas:\no recurso é essencial para a tarefa atual? existe uma alternativa com menos acesso? o usuário entende por que o pedido aparece agora? Se um app de lista de tarefas pede localização na primeira abertura, a pessoa tende a desconfiar. Se um app de delivery pede localização depois que o usuário toca em “usar endereço atual”, o contexto é claro. A permissão não deve ser um ritual técnico; deve ser consequência de uma intenção visível.\nEm Android, isso afeta métricas reais. Uma recusa permanente pode bloquear uma função importante, aumentar tickets de suporte e reduzir retenção. Por isso, permissões devem ser tratadas como parte do fluxo de produto, não como popup automático no onCreate.\nUm caso clássico é câmera: antes de abrir o preview, explique a tarefa e só então inicialize CameraX. O guia de CameraX com Jetpack Compose e Kotlin mostra esse fluxo completo.\nDeclare no Manifest apenas o necessário O primeiro passo é revisar o AndroidManifest.xml. Declare só permissões que correspondem a funcionalidades reais e ativas. Permissão esquecida no Manifest pode gerar revisão mais dura na Play Store, aumentar desconfiança e criar dívida de compliance.\n\u0026lt;manifest xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026gt; \u0026lt;uses-permission android:name=\u0026#34;android.permission.CAMERA\u0026#34; /\u0026gt; \u0026lt;uses-permission android:name=\u0026#34;android.permission.POST_NOTIFICATIONS\u0026#34; /\u0026gt; \u0026lt;uses-permission android:name=\u0026#34;android.permission.ACCESS_COARSE_LOCATION\u0026#34; /\u0026gt; \u0026lt;uses-permission android:name=\u0026#34;android.permission.ACCESS_FINE_LOCATION\u0026#34; /\u0026gt; \u0026lt;/manifest\u0026gt; Nem toda permissão declarada precisa ser solicitada na inicialização. O Manifest informa capacidade. O pedido em runtime deve acontecer no momento da ação. Para recursos opcionais, considere feature flags e telas alternativas para usuários que preferem não conceder acesso.\nRuntime permission com Activity Result API Em Kotlin moderno, evite APIs antigas como requestPermissions direto na Activity sem organização. A abordagem com Activity Result API separa o contrato de permissão e facilita testes de estado.\nclass CameraPermissionController( private val onGranted: () -\u0026gt; Unit, private val onDenied: () -\u0026gt; Unit, ) { fun handleResult(granted: Boolean) { if (granted) onGranted() else onDenied() } } Em uma Activity ou composable integrado ao lifecycle, o launcher fica responsável por abrir o diálogo do sistema:\nval launcher = rememberLauncherForActivityResult( contract = ActivityResultContracts.RequestPermission(), ) { granted -\u0026gt; if (granted) { viewModel.onCameraPermissionGranted() } else { viewModel.onCameraPermissionDenied() } } A regra importante é não espalhar lógica de negócio dentro do callback. O callback deve informar o resultado ao ViewModel ou a um controlador de UI. O ViewModel decide o próximo estado: abrir câmera, mostrar explicação, exibir alternativa ou registrar evento analítico.\nModele permissões como estado de UI Permissões têm mais estados do que “sim” e “não”. Um fluxo real pode envolver:\nainda não pedido; concedido; negado uma vez; negado com “não perguntar novamente”; indisponível no aparelho; exigindo ativação manual em configurações; permitido parcialmente, como localização aproximada. Uma modelagem explícita reduz bugs:\nsealed interface PermissionUiState { data object Unknown : PermissionUiState data object Granted : PermissionUiState data object NeedsRationale : PermissionUiState data object Denied : PermissionUiState data object PermanentlyDenied : PermissionUiState } No Compose, a tela renderiza com base nesse estado. Isso evita abrir o diálogo repetidamente em recomposição, um erro comum quando o pedido de permissão fica acoplado ao corpo do composable.\n@Composable fun CameraGate( state: PermissionUiState, onRequestPermission: () -\u0026gt; Unit, onOpenSettings: () -\u0026gt; Unit, ) { when (state) { PermissionUiState.Granted -\u0026gt; CameraContent() PermissionUiState.NeedsRationale -\u0026gt; PermissionExplanation( title = \u0026#34;Permitir câmera?\u0026#34;, text = \u0026#34;Usamos a câmera apenas para escanear o código que você escolher.\u0026#34;, primaryAction = onRequestPermission, ) PermissionUiState.PermanentlyDenied -\u0026gt; SettingsCard(onOpenSettings) else -\u0026gt; PermissionIntro(onRequestPermission) } } O pedido do sistema deve acontecer em resposta a clique, não como efeito invisível. Isso respeita o usuário e reduz surpresa.\nRationale: explique antes de insistir shouldShowRequestPermissionRationale ajuda a identificar quando o usuário negou antes e o app deveria explicar melhor. Mas não transforme isso em texto genérico. Uma boa rationale responde:\nqual recurso precisa da permissão; que dado será acessado; quando o acesso acontece; o que a pessoa perde se negar; qual alternativa existe. Ruim: “Precisamos desta permissão para continuar”.\nMelhor: “Para anexar uma foto ao chamado, o app precisa abrir a câmera. Você também pode enviar a imagem pela galeria sem permitir câmera agora.”\nEssa diferença é ainda mais importante em categorias sensíveis como saúde, finanças, família, trabalho de campo e educação. Se o app lida com dados locais, revise também segurança de dados locais no Android.\nNotificações: peça no momento de valor Desde Android 13, POST_NOTIFICATIONS exige consentimento em runtime. Muita gente implementa o pedido na primeira abertura e perde a chance de explicar valor. Em 2026, isso é uma decisão ruim para quase todo app.\nPeça notificações quando o usuário ativa algo que naturalmente gera alerta:\nacompanhar pedido; receber lembrete de estudo; monitorar vaga nova; avisar sobre vencimento; lembrar tarefa recorrente; receber status de sincronização importante. Para um app educacional em Kotlin, por exemplo, o pedido faria sentido depois que a pessoa escolhe receber lembretes de prática. Para um app de vagas, depois que ela cria um alerta. Isso aumenta consentimento porque o benefício está claro.\nTambém ofereça controle interno. Permissão do sistema não substitui preferências de produto. Um usuário pode permitir notificações gerais, mas querer desativar marketing e manter apenas alertas transacionais.\nLocalização: aproximada, precisa e background Localização é uma das permissões mais sensíveis. Use ACCESS_COARSE_LOCATION quando localização aproximada basta. Peça ACCESS_FINE_LOCATION apenas quando precisão realmente muda o resultado, como navegação, check-in geográfico ou mapa com posição exata.\nEvite pedir localização em background sem necessidade forte. Background location tem revisão mais rigorosa, exige justificativa clara e pode parecer invasiva. Muitos casos podem ser resolvidos com:\nlocalização apenas enquanto o app está em uso; endereço digitado manualmente; seleção de cidade; geocodificação aproximada; atualização sob demanda. Se o app também usa App Links, campanhas ou analytics, nunca misture localização com rastreamento sem consentimento claro. Permissão técnica não é autorização para coletar mais dado do que a função exige.\nFotos, vídeo e arquivos: prefira seletores do sistema Muitos apps ainda pedem acesso amplo ao armazenamento quando só precisam de uma foto. Em versões modernas do Android, use o Photo Picker ou contratos de seleção de conteúdo sempre que possível. O usuário escolhe arquivos específicos sem dar acesso permanente à galeria inteira.\nval pickImage = rememberLauncherForActivityResult( contract = ActivityResultContracts.PickVisualMedia(), ) { uri -\u0026gt; if (uri != null) { viewModel.onImageSelected(uri) } } Essa abordagem reduz fricção, melhora privacidade e simplifica a explicação. Em muitos fluxos, você não precisa de READ_MEDIA_IMAGES; precisa apenas deixar a pessoa escolher uma imagem.\nCâmera e microfone: deixe o escopo explícito Câmera e microfone exigem confiança. Antes de pedir, mostre a ação concreta: escanear documento, tirar foto de perfil, ler QR Code, gravar áudio ou participar de chamada. Depois de concedido, dê feedback visual claro enquanto o recurso está ativo.\nTambém trate falhas:\ncâmera indisponível; outro app usando microfone; aparelho sem sensor esperado; permissão concedida, mas feature bloqueada por política corporativa; app em modo restrito por perfil de trabalho. Esse cuidado pesa em entrevistas Android. Saber chamar uma API é básico; saber lidar com estados reais de dispositivo mostra maturidade.\nTestes de fluxo de permissão Permissões são difíceis de testar apenas com unit test, mas a regra de decisão pode ser isolada. Teste o ViewModel ou reducer que transforma resultado do sistema em estado de UI.\n@Test fun `quando usuario nega camera apos rationale mostra estado negado`() { val reducer = PermissionReducer() val state = reducer.reduce( current = PermissionUiState.NeedsRationale, event = PermissionEvent.Result(granted = false), ) assertEquals(PermissionUiState.Denied, state) } Para testes instrumentados, valide pelo menos os caminhos críticos: primeira solicitação, recusa, concessão e retorno das configurações. Em suites com Maestro ou UI Automator, mantenha esses testes pequenos e estáveis. O objetivo não é automatizar todo comportamento do diálogo do sistema, mas garantir que sua tela reage corretamente depois do resultado.\nSe o projeto já usa testes de screenshot no Compose, vale capturar os estados de explicação, negado e configurações. Esses cards costumam quebrar visualmente quando o app ganha novos idiomas, fontes maiores ou textos de compliance.\nAnalytics sem invadir privacidade Eventos de permissão ajudam produto a melhorar o fluxo, mas devem ser agregados e cuidadosos. Meça coisas como:\ntela onde o pedido aconteceu; permissão solicitada; aceite ou recusa; clique em “abrir configurações”; uso de alternativa sem permissão. Não registre dado sensível associado à permissão. Se o usuário negou localização, você não precisa guardar coordenada, endereço ou identificador pessoal para entender que o fluxo precisa de melhoria. Para comparar práticas de observabilidade e privacidade em outras stacks, o ecossistema irmão de Python para automação e dados também reforça a mesma regra: medir comportamento sem coletar mais do que o necessário.\nChecklist para produção Antes de publicar uma funcionalidade com permissão em Android Kotlin, revise:\na permissão está declarada no Manifest apenas se for necessária; o pedido acontece no momento de valor, não na primeira abertura; existe texto de rationale claro e específico; a UI trata concedido, negado, negado permanente e alternativa; o app funciona parcialmente sem a permissão quando possível; localização precisa e background só são pedidos com justificativa forte; seleção de fotos usa Photo Picker quando acesso amplo não é necessário; eventos analíticos não vazam dados sensíveis; há testes para a regra de estado e para a tela de fallback; a documentação interna explica por que cada permissão existe. Permissões bem tratadas deixam o app mais confiável, reduzem suporte e aumentam a chance de aceite quando o recurso realmente importa. Em Kotlin, a combinação de Activity Result API, ViewModel, sealed interfaces e Compose permite modelar esse fluxo de forma limpa. O desafio não é técnico apenas: é pedir acesso com respeito, no contexto certo, e manter uma alternativa honesta para quem prefere dizer não.\n","permalink":"https://kotlin.dev.br/blog/permissoes-android-kotlin-2026/","summary":"\u003cp\u003ePermissão no Android parece um detalhe de implementação até o produto perder conversão, receber avaliação ruim ou quebrar em uma atualização de sistema. Um app que pede localização antes de explicar o valor, solicita câmera sem contexto, insiste em notificação depois de uma recusa ou trata armazenamento como se ainda estivesse em 2018 transmite desconfiança. Em 2026, saber desenhar \u003cstrong\u003epermissões no Android com Kotlin\u003c/strong\u003e é parte de arquitetura, UX, segurança e carreira.\u003c/p\u003e","title":"Permissões no Android com Kotlin em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA CI\u0026T busca uma pessoa Desenvolvedora iOS Sênior para atuação remota, com base em Campinas ou em qualquer local do Brasil.\nStack e ferramentasDesenvolvimento iOS com Swift, UIKit e SwiftUI.Gerenciamento de dependências com CocoaPods e Swift Package Manager.Experiência com Kotlin e Java.Uso de GitLab, Jenkins, SonarQube e Jira.Contato com AWS Cloud, Claude Code e MCPs.FormatoNível: sênior.Modelo de trabalho: remoto.Localidade: Campinas ou Brasil. ","permalink":"https://kotlin.dev.br/vagas/ug94b6v4s065x2jd-ci-t-desenvolvedor-ios-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T busca uma pessoa \u003cstrong\u003eDesenvolvedora iOS Sênior\u003c/strong\u003e para atuação remota, com base em Campinas ou em qualquer local do Brasil.\u003c/p\u003e\u003ch3\u003eStack e ferramentas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolvimento iOS com \u003cstrong\u003eSwift\u003c/strong\u003e, \u003cstrong\u003eUIKit\u003c/strong\u003e e \u003cstrong\u003eSwiftUI\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eGerenciamento de dependências com \u003cstrong\u003eCocoaPods\u003c/strong\u003e e \u003cstrong\u003eSwift Package Manager\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eJava\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eGitLab\u003c/strong\u003e, \u003cstrong\u003eJenkins\u003c/strong\u003e, \u003cstrong\u003eSonarQube\u003c/strong\u003e e \u003cstrong\u003eJira\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eContato com \u003cstrong\u003eAWS Cloud\u003c/strong\u003e, \u003cstrong\u003eClaude Code\u003c/strong\u003e e \u003cstrong\u003eMCPs\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFormato\u003c/h3\u003e\u003cul\u003e\u003cli\u003eNível: sênior.\u003c/li\u003e\u003cli\u003eModelo de trabalho: remoto.\u003c/li\u003e\u003cli\u003eLocalidade: Campinas ou Brasil.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor iOS Sênior"},{"content":"Sobre a vagaA CI\u0026amp;T busca uma pessoa Desenvolvedora iOS Sênior para atuação remota no Brasil, com possibilidade de referência em Campinas.\nTecnologias e stackSwift, UIKit e SwiftUIKotlin, REST, MVVM, Clean Architecture, PoP e Coordinatorswinject, SwiftDependencies, Push Notifications, SQLite e localizaçãoCI/CD, Azure, AWS, EKS, ECS, AWS Lambda e API ManagementPostgreSQL, Oracle, Couchbase, EntraID, ForgeRock e DynatraceSCM, XCTest e bibliotecas iOSRequisitosExperiência sênior em desenvolvimento iOS.Conhecimento em arquitetura mobile, testes e integração contínua.Experiência com consumo de APIs REST e persistência local. ","permalink":"https://kotlin.dev.br/vagas/fr5ckse1r1bvt7qs-ci-t-desenvolvedor-a-ios-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026amp;T busca uma pessoa Desenvolvedora iOS Sênior para atuação remota no Brasil, com possibilidade de referência em Campinas.\u003c/p\u003e\u003ch3\u003eTecnologias e stack\u003c/h3\u003e\u003cul\u003e\u003cli\u003eSwift, UIKit e SwiftUI\u003c/li\u003e\u003cli\u003eKotlin, REST, MVVM, Clean Architecture, PoP e Coordinator\u003c/li\u003e\u003cli\u003eswinject, SwiftDependencies, Push Notifications, SQLite e localização\u003c/li\u003e\u003cli\u003eCI/CD, Azure, AWS, EKS, ECS, AWS Lambda e API Management\u003c/li\u003e\u003cli\u003ePostgreSQL, Oracle, Couchbase, EntraID, ForgeRock e Dynatrace\u003c/li\u003e\u003cli\u003eSCM, XCTest e bibliotecas iOS\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento iOS.\u003c/li\u003e\u003cli\u003eConhecimento em arquitetura mobile, testes e integração contínua.\u003c/li\u003e\u003cli\u003eExperiência com consumo de APIs REST e persistência local.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) iOS Sênior"},{"content":"Sobre a vagaA Kevel busca uma pessoa Engenheira Principal para uma vaga remota de nível sênior, com atuação em ambientes JVM e infraestrutura em nuvem.\nTecnologias mencionadasKotlin, Java, Scala, Clojure, Rust e Node.jsJVMAWS e GCPAWS CDK, CDKTF e TerraformLocalizaçãoVaga remota para pessoas no Brasil, Durham, Estados Unidos, Reino Unido, Portugal ou Singapura.\n","permalink":"https://kotlin.dev.br/vagas/mw6ysy0uqz3x0hq8-kevel-engenheiro-a-principal/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Kevel busca uma pessoa Engenheira Principal para uma vaga remota de nível sênior, com atuação em ambientes JVM e infraestrutura em nuvem.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java, Scala, Clojure, Rust e Node.js\u003c/li\u003e\u003cli\u003eJVM\u003c/li\u003e\u003cli\u003eAWS e GCP\u003c/li\u003e\u003cli\u003eAWS CDK, CDKTF e Terraform\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocalização\u003c/h3\u003e\u003cp\u003eVaga remota para pessoas no Brasil, Durham, Estados Unidos, Reino Unido, Portugal ou Singapura.\u003c/p\u003e","title":"Engenheiro(a) Principal"},{"content":"Sobre a vagaO iFood busca uma pessoa Gerente de Engenharia de Software Backend, em nível sênior, para atuar presencialmente em Osasco, São Paulo.\nResponsabilidadesLiderar uma equipe de engenharia backend, apoiando entregas, qualidade técnica e evolução das pessoas.Orientar decisões de arquitetura e desenvolvimento de serviços backend.Trabalhar com sistemas distribuídos, mensageria, infraestrutura em nuvem e observabilidade.Colaborar com áreas de produto e tecnologia para priorizar iniciativas e remover impedimentos.RequisitosExperiência sênior em engenharia de software e liderança de times backend.Vivência com Kotlin, Go e serviços em AWS.Conhecimento de mensageria com SNS e SQS.Experiência com EKS e práticas de observabilidade usando DataDog e Grafana.TecnologiasKotlinGoAWSSNS e SQSEKSDataDogGrafana ","permalink":"https://kotlin.dev.br/vagas/yo5rau2pxcuvny5r-ifood-gerente-de-engenharia-de-software-backend/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa \u003cstrong\u003eGerente de Engenharia de Software Backend\u003c/strong\u003e, em nível sênior, para atuar presencialmente em Osasco, São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLiderar uma equipe de engenharia backend, apoiando entregas, qualidade técnica e evolução das pessoas.\u003c/li\u003e\u003cli\u003eOrientar decisões de arquitetura e desenvolvimento de serviços backend.\u003c/li\u003e\u003cli\u003eTrabalhar com sistemas distribuídos, mensageria, infraestrutura em nuvem e observabilidade.\u003c/li\u003e\u003cli\u003eColaborar com áreas de produto e tecnologia para priorizar iniciativas e remover impedimentos.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software e liderança de times backend.\u003c/li\u003e\u003cli\u003eVivência com Kotlin, Go e serviços em AWS.\u003c/li\u003e\u003cli\u003eConhecimento de mensageria com SNS e SQS.\u003c/li\u003e\u003cli\u003eExperiência com EKS e práticas de observabilidade usando DataDog e Grafana.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eGo\u003c/li\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eSNS e SQS\u003c/li\u003e\u003cli\u003eEKS\u003c/li\u003e\u003cli\u003eDataDog\u003c/li\u003e\u003cli\u003eGrafana\u003c/li\u003e\u003c/ul\u003e","title":"Gerente de Engenharia de Software Backend"},{"content":"Sobre a vagaO C6 Bank busca uma Pessoa Desenvolvedora Especialista Java/Kotlin para a área de Corporate Banking Engineering.\nInformações da vagaSenioridade: SêniorModelo de trabalho: PresencialLocal: São Paulo, São Paulo, BrasilTecnologias mencionadas: Java e Kotlin ","permalink":"https://kotlin.dev.br/vagas/mlco2y5uaotj4unc-c6-bank-pessoa-desenvolvedora-especialista-java-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma Pessoa Desenvolvedora Especialista Java/Kotlin para a área de Corporate Banking Engineering.\u003c/p\u003e\u003ch3\u003eInformações da vaga\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eSenioridade:\u003c/strong\u003e Sênior\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eModelo de trabalho:\u003c/strong\u003e Presencial\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eLocal:\u003c/strong\u003e São Paulo, São Paulo, Brasil\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eTecnologias mencionadas:\u003c/strong\u003e Java e Kotlin\u003c/li\u003e\u003c/ul\u003e","title":"Pessoa Desenvolvedora Especialista Java/Kotlin"},{"content":"O Kotlin 2.2 chegou para consolidar tendências que vinham se desenhando desde o trabalho pesado do compilador K2. Se o Kotlin 2.1 marcou a maturidade do K2 como padrão e a estabilização de guard conditions, o 2.2 é a versão em que recursos antes experimentais finalmente viram ferramenta de produção — em especial os context parameters, que substituem os antigos context receivers com uma sintaxe mais limpa e segura.\nNeste guia, você vai ver o que realmente muda no seu código, com exemplos práticos. A ideia é fugir do marketing e focar no que afeta o dia a dia de quem mantém apps Android, backends em Spring ou Ktor e bibliotecas multiplataforma. Se você quer uma visão mais ampla do ecossistema, vale revisar também o nosso panorama de novidades do Kotlin em 2026 e o guia completo de KSP, que ganhou performance extra nesta versão.\n1. Context Parameters: o recurso central do Kotlin 2.2 O maior destaque do Kotlin 2.2 é a estabilização dos context parameters. Eles resolvem um problema clássico: como passar dependências implícitas (um CoroutineScope, um Logger, um receptor de DSL) sem poluir a assinatura de cada função e sem apelar para threads locais mutáveis.\nAntes do 2.2 existiam os context receivers, que eram experimentais e tinham limitações confusas de resolução de ambiguidade. O novo mecanismo é mais explícito:\ncontext(scope: CoroutineScope, logger: Logger) fun saveUser(user: User) { launch { logger.info(\u0026#34;Salvando ${user.id}\u0026#34;) repository.put(user) } } Aqui scope e logger são declarados como parâmetros de contexto. Para chamar saveUser, você precisa de um CoroutineScope e de um Logger no escopo da chamada, o que o compilador verifica estaticamente. A diferença para os context receivers antigos é que agora há nomes explícitos e regras claras de precedência, o que elimina a maior parte dos erros difíceis de debugar.\nComo prover um contexto O contexto é fornecido por uma extensão marcada com context no próprio receptor, ou por um bloco with:\nwith(MyAppScope, consoleLogger) { saveUser(currentUser) // resolve scope e logger automaticamente } O ganho prático aparece em código de biblioteca e em DSLs. Em vez de repetir o mesmo Receiver em dezenas de funções internas, você declara uma vez e o compilador propaga. Para aprofundar o padrão de DSL, veja o nosso tutorial de extension functions e o guia de Kotlin DSL do Gradle, onde context parameters deixam o código idiomático consideravelmente mais limpo.\nMigração dos context receivers antigos Se você usava context receivers experimentais, a migração é direta mas não é só renomear. As principais mudanças:\nA cláusula context(...) agora exige nomes (context(logger: Logger)), não apenas tipos. Quando há ambiguidade de contexto, o compilador aponta explicitamente qual nome resolver — antes era um erro vago. O modificador -Xcontext-receivers foi substituído por -Xcontext-parameters, e o antigo emite warning de depreciação. Rode o build com a flag nova, corrija os nomes ausentes e remova o flag antigo do build.gradle.kts. A maioria dos projetos migra em poucas horas.\n2. Smart cast mais inteligente e abrangente O Kotlin sempre teve smart cast, mas havia buracos irritantes: propriedades val mutáveis de outras classes, resultados de \u0026amp;\u0026amp; curto-circuitado e desestruturação de data classes nem sempre eram reconhecidos. O 2.2 estreia um smart-cast reformulado por cima do K2 que cobre vários desses casos.\nAntes, este código precisava de cast explícito ou de uma variável local temporária:\nclass Container { val value: Any? = compute() } fun handle(c: Container) { if (c.value is String) { // antes: precisava de (c.value as String) println(c.value.length) } } No Kotlin 2.2, desde que o val seja efetivamente imutável durante a análise, o smart cast é aplicado diretamente. O mesmo vale para combinar null checks encadeados:\nfun process(user: User?, settings: Settings?) { if (user != null \u0026amp;\u0026amp; settings != null \u0026amp;\u0026amp; settings.strict) { // user e settings são non-null aqui, mesmo sendo parâmetros nullable user.notify(settings) } } Isso reduz ruído visual e diminui o número de warnings de CastCanBeNull. Para quem mantém código legado cheio de let, vale revisar nosso guia de null safety para identificar onde os casts explícitos viraram desnecessários.\n3. Melhorias no compilador K2 e tempos de build O K2 já era o padrão, mas o 2.2 traz otimizações específicas de backend que afetam projetos grandes. Os destaques mensurados:\nRedução de 10% a 15% no tempo de compilação incremental em monorepos, especialmente quando há muitos módulos KMP. Melhor cache de inferência de tipos, evitando recomputar árvores inteiras após pequenas edições. Diagnósticos mais precisos: mensagens de erro agora apontam o local exato na expressão em vez de só marcar a função inteira. Se você usa Gradle Version Catalogs e build cache distribuído, o ganho compõe: o K2 mais rápido reduz o custo de cache misses. Para times que medem CI, a dica é comparar o compileKotlin antes e depois da migração usando o relatório do Gradle.\n4. Multi-dollar string interpolation refinada O 2.1 introduziu a interpolação com múltiplos cifrões ($$). O 2.2 refinou as regras de escape para evitar armadilhas comuns — em especial quando o conteúdo interpolado contém chaves ou expressões com $:\nval amount = 1_000 val currency = \u0026#34;BRL\u0026#34; // interpolacao multi-dollar permite expressoes complexas sem escape val msg = $$\u0026#34;Total: ${formatCurrency(amount, currency)} (taxa incluída)\u0026#34; As regras agora são: dentro de $$\u0026quot;...\u0026quot;, o ${...} é sempre tratado como interpolação Kotlin, e um $ sozinho é literal. Antes, misturar ${} com texto que continha cifrões (como valores monetários) quebrava o build. Isso é especialmente útil em templates de relatório, SQL gerado e mensagens de log estruturadas.\n5. AutoCloseable e cleanup determinístico O Kotlin 2.2 padroniza o uso de AutoCloseable com uma extensão use aprimorada e suporte a try-with-resources mais idiomático. A novidade é que agora qualquer classe que implemente AutoCloseable pode ser combinada com ScopedValue-like patterns via context parameters:\ncontext(db: Database) fun findAll(): List\u0026lt;User\u0026gt; = db.query(\u0026#34;SELECT * FROM users\u0026#34;) fun main() = Database.connect(url).use { db -\u0026gt; with(db) { findAll().forEach { println(it) } } } O use garante o fechamento mesmo em exceções, e o contexto elimina a necessidade de passar db explicitamente para cada função do domínio. É um padrão forte para backends em Ktor e Spring Boot, onde o gerenciamento de conexões era sempre um boilerplate chato.\n6. Kotlin/Wasm e Kotlin/JS Continua a estabilização de Kotlin/Wasm. O 2.2 marca o target Wasm como estável para apps Compose Multiplatform Web, com garbage collector padrão e suporte completo a source maps. Para Kotlin/JS, o foco foi reduzir o tamanho de bundle com tree-shaking mais agressivo.\nPara quem compara caminhos de frontend multiplataforma, é útil cruzar com o Kotlin vs TypeScript: enquanto TypeScript segue dominando a web, Kotlin/Wasm abre espaço para compartilhar lógica de domínio entre Android, iOS e Web sem reescrever em JS.\nComo migrar para o Kotlin 2.2 A migração é direta para a maioria dos projetos. Passos recomendados:\nAtualize o plugin Kotlin no build.gradle.kts para 2.2.x e o Gradle para a versão mínima suportada. Ative context parameters adicionando -Xcontext-parameters em kotlinOptions.freeCompilerArgs (e remova -Xcontext-receivers). Rode o inspetor de ABI com :check para detectar mudanças incompatíveis em bibliotecas internas. Revise smart casts removidos: o que antes exigia as pode ser limpo, mas falso positivos podem mascarar bugs — rode os testes. Atualize dependências que dependem do compilador (KSP, Room, Hilt, Moshi) para versões compatíveis com Kotlin 2.2. Para apps Android, atualize o Android Studio para a versão que suporta o plugin Kotlin 2.2 e sincronize o projeto. Times que usam Hilt devem aguardar a release compatível do Hilt-KSP, que costuma sair poucas semanas depois da linguagem.\nVale a pena migrar agora? Para bibliotecas e novos projetos, sim — context parameters e o smart cast melhorado valem a pena desde o primeiro commit. Para apps em produção estáveis, a migração pode esperar o ponto de release dos principais processadores de anotação, mas planeje para o próximo trimestre. O risco de ficar em 2.1 por muito tempo é acumular débito de features e perder ganhos de produtividade que já estão maduros.\nSe você compara Kotlin com outras linguagens do ecossistema backend, vale olhar o Kotlin vs Go e o Kotlin vs Rust. Quem busca desempenho bruto em concorrência pode complementar com Go para serviços de alto throughput, ou Rust para componentes de baixo nível — e em pipelines de dados, Python segue sendo a escolha para ML e ciência de dados.\nConclusão O Kotlin 2.2 não é uma revolução: é uma versão de consolidação. Context parameters estáveis finalmente resolvem um problema de ergonomia que a comunidade pediu por anos, o smart cast reformulado remove código redundante, e o K2 continua ficando mais rápido. Para quem já estava em 2.1, a migração é de baixo risco e alto retorno em legibilidade.\nA recomendação prática é: migre bibliotecas e projetos novos imediatamente, agende a migração de apps estáveis para o próximo ciclo de release, e comece a refatorar context receivers experimentais assim que possível, antes que a depreciação vire erro. O ecossistema — Spring, Ktor, Compose, KMP — já está preparado, então não há razão para segurar.\n","permalink":"https://kotlin.dev.br/blog/kotlin-22-context-parameters-smart-cast-2026/","summary":"\u003cp\u003eO Kotlin 2.2 chegou para consolidar tendências que vinham se desenhando desde o trabalho pesado do compilador K2. Se o \u003ca href=\"/blog/kotlin-21-novidades-2026/\"\u003eKotlin 2.1\u003c/a\u003e marcou a maturidade do K2 como padrão e a estabilização de guard conditions, o 2.2 é a versão em que recursos antes experimentais finalmente viram ferramenta de produção — em especial os \u003cstrong\u003econtext parameters\u003c/strong\u003e, que substituem os antigos context receivers com uma sintaxe mais limpa e segura.\u003c/p\u003e\n\u003cp\u003eNeste guia, você vai ver o que realmente muda no seu código, com exemplos práticos. A ideia é fugir do marketing e focar no que afeta o dia a dia de quem mantém apps Android, backends em Spring ou Ktor e bibliotecas multiplataforma. Se você quer uma visão mais ampla do ecossistema, vale revisar também o nosso panorama de \u003ca href=\"/blog/kotlin-2026-novidades/\"\u003enovidades do Kotlin em 2026\u003c/a\u003e e o \u003ca href=\"/blog/kotlin-ksp-guia-completo/\"\u003eguia completo de KSP\u003c/a\u003e, que ganhou performance extra nesta versão.\u003c/p\u003e","title":"Kotlin 2.2: Context Parameters, Smart Cast e o Que Muda no Seu Código | Kotlin Brasil"},{"content":"Sobre a vagaA Experian busca uma pessoa Analista de Desenvolvimento de Software C/C++ Sênior para atuação híbrida em Blumenau, Santa Catarina.\nTecnologias e contextoDesenvolvimento com C e C++ em ambiente Linux.Atuação com soluções de pagamento, incluindo POS, TEF, EMV e PCI-DSS.Contato com plataformas e dispositivos como PAX, Ingenico, Gertec e Verifone.Conhecimentos relacionados a Java, Kotlin e Android.RequisitosExperiência sênior em desenvolvimento de software.Experiência com C/C++ e Linux.Vivência ou interesse em meios de pagamento, POS e TEF.Disponibilidade para modelo híbrido em Blumenau. ","permalink":"https://kotlin.dev.br/vagas/e643nh9u902yse03-experian-analista-de-desenvolvimento-de-software-c-c-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Experian busca uma pessoa Analista de Desenvolvimento de Software C/C++ Sênior para atuação híbrida em Blumenau, Santa Catarina.\u003c/p\u003e\u003ch3\u003eTecnologias e contexto\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolvimento com \u003cstrong\u003eC\u003c/strong\u003e e \u003cstrong\u003eC++\u003c/strong\u003e em ambiente \u003cstrong\u003eLinux\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eAtuação com soluções de pagamento, incluindo \u003cstrong\u003ePOS\u003c/strong\u003e, \u003cstrong\u003eTEF\u003c/strong\u003e, \u003cstrong\u003eEMV\u003c/strong\u003e e \u003cstrong\u003ePCI-DSS\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eContato com plataformas e dispositivos como \u003cstrong\u003ePAX\u003c/strong\u003e, \u003cstrong\u003eIngenico\u003c/strong\u003e, \u003cstrong\u003eGertec\u003c/strong\u003e e \u003cstrong\u003eVerifone\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimentos relacionados a \u003cstrong\u003eJava\u003c/strong\u003e, \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eAndroid\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento de software.\u003c/li\u003e\u003cli\u003eExperiência com C/C++ e Linux.\u003c/li\u003e\u003cli\u003eVivência ou interesse em meios de pagamento, POS e TEF.\u003c/li\u003e\u003cli\u003eDisponibilidade para modelo híbrido em Blumenau.\u003c/li\u003e\u003c/ul\u003e","title":"Analista de Desenvolvimento de Software C/C++ Sênior"},{"content":"Sobre a vagaA Experian busca uma pessoa Analista de Desenvolvimento Smart POS Pleno para atuação híbrida em Blumenau, Santa Catarina.\nAtuaçãoDesenvolvimento de soluções para Smart POS.Trabalho com integrações via REST APIs.Aplicação de padrões como MVVM e Clean Architecture.Uso de ferramentas de observabilidade e diagnóstico, como Datadog e Crashlytics.RequisitosExperiência com Java e Kotlin.Conhecimento em Flutter.Experiência com Git.Conhecimento em CliSiTef.Familiaridade com arquitetura MVVM e Clean Architecture.Local de trabalhoModelo híbrido em Blumenau, Santa Catarina, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/0bioa6tzd4l402du-experian-analista-de-desenvolvimento-smart-pos-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Experian busca uma pessoa Analista de Desenvolvimento Smart POS Pleno para atuação híbrida em Blumenau, Santa Catarina.\u003c/p\u003e\u003ch3\u003eAtuação\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolvimento de soluções para Smart POS.\u003c/li\u003e\u003cli\u003eTrabalho com integrações via REST APIs.\u003c/li\u003e\u003cli\u003eAplicação de padrões como MVVM e Clean Architecture.\u003c/li\u003e\u003cli\u003eUso de ferramentas de observabilidade e diagnóstico, como Datadog e Crashlytics.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Java e Kotlin.\u003c/li\u003e\u003cli\u003eConhecimento em Flutter.\u003c/li\u003e\u003cli\u003eExperiência com Git.\u003c/li\u003e\u003cli\u003eConhecimento em CliSiTef.\u003c/li\u003e\u003cli\u003eFamiliaridade com arquitetura MVVM e Clean Architecture.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eModelo híbrido em Blumenau, Santa Catarina, Brasil.\u003c/p\u003e","title":"Analista de Desenvolvimento Smart POS Pleno"},{"content":"Sobre a vagaA Applaudo busca uma pessoa sênior para atuar como Arquiteto de Aplicações Android em uma posição remota baseada em Bogotá, Colômbia.\nRequisitos e tecnologiasExperiência sênior com arquitetura de aplicações Android.Conhecimento em Kotlin para desenvolvimento Android.Experiência com MDM e Kiosk Mode.Conhecimento em BFF (Backend for Frontend).Noções de JavaScript e CSS.Conhecimento em segurança mobile, incluindo OWASP Mobile Top 10.Atenção a acessibilidade conforme WCAG 2.1 nível AA.Formato de trabalhoVaga remota para profissional de nível sênior. A descrição original não informa responsabilidades detalhadas ou benefícios específicos.\n","permalink":"https://kotlin.dev.br/vagas/i7j65r4pharimefd-applaudo-arquiteto-de-aplicacoes-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Applaudo busca uma pessoa sênior para atuar como \u003cstrong\u003eArquiteto de Aplicações Android\u003c/strong\u003e em uma posição remota baseada em Bogotá, Colômbia.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com arquitetura de aplicações Android.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e para desenvolvimento Android.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eMDM\u003c/strong\u003e e \u003cstrong\u003eKiosk Mode\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eBFF (Backend for Frontend)\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eNoções de \u003cstrong\u003eJavaScript\u003c/strong\u003e e \u003cstrong\u003eCSS\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em segurança mobile, incluindo \u003cstrong\u003eOWASP Mobile Top 10\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eAtenção a acessibilidade conforme \u003cstrong\u003eWCAG 2.1 nível AA\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFormato de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissional de nível sênior. A descrição original não informa responsabilidades detalhadas ou benefícios específicos.\u003c/p\u003e","title":"Arquiteto de Aplicações Android"},{"content":"Sobre a vagaA Applaudo busca uma pessoa Desenvolvedora Android Pleno para atuação remota a partir de Bogotá, Colômbia.\nRequisitosExperiência com desenvolvimento Android usando Kotlin.Conhecimento de Android SDK e Android WebView.Familiaridade com JavaScript e CSS em contextos de WebView ou integração web.Uso de Git no fluxo de desenvolvimento.Modelo de trabalhoRemoto.Nível de senioridade: Pleno. ","permalink":"https://kotlin.dev.br/vagas/l5syumaj1cv3i9co-applaudo-desenvolvedor-android-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Applaudo busca uma pessoa Desenvolvedora Android Pleno para atuação remota a partir de Bogotá, Colômbia.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com desenvolvimento Android usando \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento de \u003cstrong\u003eAndroid SDK\u003c/strong\u003e e \u003cstrong\u003eAndroid WebView\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eFamiliaridade com \u003cstrong\u003eJavaScript\u003c/strong\u003e e \u003cstrong\u003eCSS\u003c/strong\u003e em contextos de WebView ou integração web.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eGit\u003c/strong\u003e no fluxo de desenvolvimento.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eRemoto.\u003c/li\u003e\u003cli\u003eNível de senioridade: Pleno.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android Pleno"},{"content":"Sobre a vagaA GFT busca Desenvolvedor(a) Angular/AWS Pleno/Sênior para atuação presencial em Barueri, São Paulo. A posição envolve desenvolvimento front-end com Angular 15+ e integração com serviços, APIs e arquitetura em nuvem AWS.\nResponsabilidadesDesenvolver e manter aplicações com Angular 15+.Trabalhar com WebView, Module Federation e arquitetura de micro frontends.Integrar aplicações com BFFs, APIs RESTful e microsserviços.Apoiar a evolução de soluções em AWS, incluindo S3, CloudFront, Lambda, API Gateway, ECS, EC2 e KMS.Contribuir com automação, CI/CD, infraestrutura como código com Terraform e monitoramento com Datadog.Aplicar boas práticas de versionamento com Git, GitHub e GitFlow.Criar e manter testes com Jest e Cypress.RequisitosExperiência de nível pleno ou sênior com Angular 15+.Conhecimento em micro frontends, Module Federation e integração via APIs REST.Experiência com AWS e serviços como S3, CloudFront, Lambda, API Gateway, ECS, EC2 e KMS.Vivência com Terraform e pipelines de CI/CD.Experiência com Git, GitHub e fluxo GitFlow.Conhecimento em testes automatizados com Jest e Cypress.Familiaridade com Kotlin em ambientes de integração ou backend.DiferenciaisConhecimento em Google Analytics 4 (GA4).Experiência com Itaú Design System, IDS ou IDL.Contato com ferramentas ou componentes internos como Caronte. ","permalink":"https://kotlin.dev.br/vagas/pk28x687ozv3iu0o-gft-desenvolvedor-a-angular-aws-pleno-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA GFT busca Desenvolvedor(a) Angular/AWS Pleno/Sênior para atuação presencial em Barueri, São Paulo. A posição envolve desenvolvimento front-end com Angular 15+ e integração com serviços, APIs e arquitetura em nuvem AWS.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações com Angular 15+.\u003c/li\u003e\u003cli\u003eTrabalhar com WebView, Module Federation e arquitetura de micro frontends.\u003c/li\u003e\u003cli\u003eIntegrar aplicações com BFFs, APIs RESTful e microsserviços.\u003c/li\u003e\u003cli\u003eApoiar a evolução de soluções em AWS, incluindo S3, CloudFront, Lambda, API Gateway, ECS, EC2 e KMS.\u003c/li\u003e\u003cli\u003eContribuir com automação, CI/CD, infraestrutura como código com Terraform e monitoramento com Datadog.\u003c/li\u003e\u003cli\u003eAplicar boas práticas de versionamento com Git, GitHub e GitFlow.\u003c/li\u003e\u003cli\u003eCriar e manter testes com Jest e Cypress.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência de nível pleno ou sênior com Angular 15+.\u003c/li\u003e\u003cli\u003eConhecimento em micro frontends, Module Federation e integração via APIs REST.\u003c/li\u003e\u003cli\u003eExperiência com AWS e serviços como S3, CloudFront, Lambda, API Gateway, ECS, EC2 e KMS.\u003c/li\u003e\u003cli\u003eVivência com Terraform e pipelines de CI/CD.\u003c/li\u003e\u003cli\u003eExperiência com Git, GitHub e fluxo GitFlow.\u003c/li\u003e\u003cli\u003eConhecimento em testes automatizados com Jest e Cypress.\u003c/li\u003e\u003cli\u003eFamiliaridade com Kotlin em ambientes de integração ou backend.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eConhecimento em Google Analytics 4 (GA4).\u003c/li\u003e\u003cli\u003eExperiência com Itaú Design System, IDS ou IDL.\u003c/li\u003e\u003cli\u003eContato com ferramentas ou componentes internos como Caronte.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Angular/AWS Pleno/Sênior"},{"content":"Sobre a vagaA CI\u0026amp;T busca uma pessoa Desenvolvedora Java Sênior para atuação remota no Brasil.\nTecnologias mencionadasJavaSpring BootKotlinReactNext.jsGraphQLAzureDatadog e APMSenioridade e modelo de trabalhoNível sênior.Trabalho remoto no Brasil. ","permalink":"https://kotlin.dev.br/vagas/kennxrkv82bq71v7-ci-t-desenvolvedor-a-java-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026amp;T busca uma pessoa Desenvolvedora Java Sênior para atuação remota no Brasil.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eSpring Boot\u003c/li\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eReact\u003c/li\u003e\u003cli\u003eNext.js\u003c/li\u003e\u003cli\u003eGraphQL\u003c/li\u003e\u003cli\u003eAzure\u003c/li\u003e\u003cli\u003eDatadog e APM\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade e modelo de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eNível sênior.\u003c/li\u003e\u003cli\u003eTrabalho remoto no Brasil.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Java Sênior"},{"content":"Sobre a vagaA SumUp busca uma pessoa Engenheira Backend Sênior para atuação presencial em Florianópolis ou São Paulo.\nStack informadaKotlinJavaAWSFormato de trabalhoVaga presencial, com possibilidade de atuação em Florianópolis ou São Paulo.\n","permalink":"https://kotlin.dev.br/vagas/gomwjgbh71xivoda-sumup-engenheiro-a-backend-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA SumUp busca uma pessoa Engenheira Backend Sênior para atuação presencial em Florianópolis ou São Paulo.\u003c/p\u003e\u003ch3\u003eStack informada\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eAWS\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFormato de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial, com possibilidade de atuação em Florianópolis ou São Paulo.\u003c/p\u003e","title":"Engenheiro(a) Backend Sênior"},{"content":"Sobre a vagaA CI\u0026T está recrutando um Senior Backend Developer experiente em Java e Kotlin para desenvolver e arquitetar soluções backend robustas e escaláveis.\nResponsabilidadesArquitetar e desenvolver serviços backend utilizando Kotlin e Java 11Trabalhar com Spring Boot e frameworks relacionadosImplementar e manter pipelines de integração contínua/entrega contínuaColaborar com equipes multidisciplinares para definir requisitos técnicosOtimizar performance e escalabilidade das aplicaçõesContribuir com code reviews e boas práticas de desenvolvimentoRequisitosExperiência sênior em desenvolvimento backend com Kotlin/JavaProfundo conhecimento em Spring BootExperiência com arquitetura de microsserviçosDomínio em PostgreSQL e design de bancos de dadosConhecimento em Docker e KubernetesExperiência com plataformas cloud (Google Cloud ou AWS)Familiaridade com ferramentas de observabilidade (Grafana, Splunk)Versionamento com Git e Git FlowDiferenciaisExperiência com Kafka e processamento de eventosConhecimento em Apigee ou API managementFamiliaridade com ferramentas AWS (SQS, SNS, Athena)Experiência com Javalin ou frameworks alternativosDocumentação com Swagger/OpenAPI ","permalink":"https://kotlin.dev.br/vagas/9hbbl6haot563xqi-ci-t-senior-backend-developer-java-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T está recrutando um Senior Backend Developer experiente em Java e Kotlin para desenvolver e arquitetar soluções backend robustas e escaláveis.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eArquitetar e desenvolver serviços backend utilizando Kotlin e Java 11\u003c/li\u003e\u003cli\u003eTrabalhar com Spring Boot e frameworks relacionados\u003c/li\u003e\u003cli\u003eImplementar e manter pipelines de integração contínua/entrega contínua\u003c/li\u003e\u003cli\u003eColaborar com equipes multidisciplinares para definir requisitos técnicos\u003c/li\u003e\u003cli\u003eOtimizar performance e escalabilidade das aplicações\u003c/li\u003e\u003cli\u003eContribuir com code reviews e boas práticas de desenvolvimento\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento backend com Kotlin/Java\u003c/li\u003e\u003cli\u003eProfundo conhecimento em Spring Boot\u003c/li\u003e\u003cli\u003eExperiência com arquitetura de microsserviços\u003c/li\u003e\u003cli\u003eDomínio em PostgreSQL e design de bancos de dados\u003c/li\u003e\u003cli\u003eConhecimento em Docker e Kubernetes\u003c/li\u003e\u003cli\u003eExperiência com plataformas cloud (Google Cloud ou AWS)\u003c/li\u003e\u003cli\u003eFamiliaridade com ferramentas de observabilidade (Grafana, Splunk)\u003c/li\u003e\u003cli\u003eVersionamento com Git e Git Flow\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kafka e processamento de eventos\u003c/li\u003e\u003cli\u003eConhecimento em Apigee ou API management\u003c/li\u003e\u003cli\u003eFamiliaridade com ferramentas AWS (SQS, SNS, Athena)\u003c/li\u003e\u003cli\u003eExperiência com Javalin ou frameworks alternativos\u003c/li\u003e\u003cli\u003eDocumentação com Swagger/OpenAPI\u003c/li\u003e\u003c/ul\u003e","title":"Senior Backend Developer Java/Kotlin"},{"content":"Sobre a vagaBuscamos um Senior Backend Developer com forte experiência em Kotlin e Java para atuar no desenvolvimento de soluções backend escaláveis e robustas.\nResponsabilidadesProjetar e desenvolver serviços backend com Kotlin/JavaTrabalhar com arquiteturas distribuídas e microsserviçosImplementar soluções utilizando Spring Boot e frameworks relacionadosColaborar com times multidisciplinaresGarantir qualidade de código e boas práticas de engenhariaRequisitosExperiência sênior com Kotlin ou JavaSólido conhecimento em Spring BootExperiência com sistemas distribuídos e arquitetura de microsserviçosProficiência com ferramentas de versionamento (Git, Git Flow)Conhecimento de Docker e KubernetesExperiência com PostgreSQL ou bancos de dados relacionaisDiferenciaisExperiência com Kafka para processamento de eventosConhecimento em cloud computing (Google Cloud, AWS)Experiência com ferramentas de monitoramento (Grafana, Splunk)Familiaridade com API management (Apigee)Conhecimento em Node.js ","permalink":"https://kotlin.dev.br/vagas/f17qkoohk6oi3lzy-ci-t-senior-backend-developer-java-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Senior Backend Developer com forte experiência em Kotlin e Java para atuar no desenvolvimento de soluções backend escaláveis e robustas.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eProjetar e desenvolver serviços backend com Kotlin/Java\u003c/li\u003e\u003cli\u003eTrabalhar com arquiteturas distribuídas e microsserviços\u003c/li\u003e\u003cli\u003eImplementar soluções utilizando Spring Boot e frameworks relacionados\u003c/li\u003e\u003cli\u003eColaborar com times multidisciplinares\u003c/li\u003e\u003cli\u003eGarantir qualidade de código e boas práticas de engenharia\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com Kotlin ou Java\u003c/li\u003e\u003cli\u003eSólido conhecimento em Spring Boot\u003c/li\u003e\u003cli\u003eExperiência com sistemas distribuídos e arquitetura de microsserviços\u003c/li\u003e\u003cli\u003eProficiência com ferramentas de versionamento (Git, Git Flow)\u003c/li\u003e\u003cli\u003eConhecimento de Docker e Kubernetes\u003c/li\u003e\u003cli\u003eExperiência com PostgreSQL ou bancos de dados relacionais\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kafka para processamento de eventos\u003c/li\u003e\u003cli\u003eConhecimento em cloud computing (Google Cloud, AWS)\u003c/li\u003e\u003cli\u003eExperiência com ferramentas de monitoramento (Grafana, Splunk)\u003c/li\u003e\u003cli\u003eFamiliaridade com API management (Apigee)\u003c/li\u003e\u003cli\u003eConhecimento em Node.js\u003c/li\u003e\u003c/ul\u003e","title":"Senior Backend Developer Java/Kotlin"},{"content":"Sobre a vagaA Amazon busca um Desenvolvedor de Software Mid Level para integrar o time de IES Latech Latam em Belo Horizonte. Você atuará no desenvolvimento de soluções robustas e escaláveis utilizando múltiplas linguagens de programação e tecnologias cloud.\nResponsabilidadesDesenvolver e manter aplicações de software em ambiente de produçãoColaborar com times multidisciplinares em projetos de infraestrutura e serviços webImplementar soluções seguindo princípios de OOP e boas práticas de códigoParticipar de ciclos de desenvolvimento ágil (Scrum, Kanban)RequisitosExperiência profissional em desenvolvimento de software (Mid Level)Proficiência em uma ou mais linguagens: Java, Kotlin, Python, Go, C/C++ ou JavaScriptConhecimento em banco de dados e serviços webExperiência com Linux/UNIXFamiliaridade com metodologias ágeis (Scrum, Kanban, XP)DiferenciaisExperiência com AWS e infraestrutura cloudConhecimento em Clojure ou outras linguagens funcionaisExperiência com RUP ou outros processos de engenharia de software ","permalink":"https://kotlin.dev.br/vagas/0hu2gizps815scdg-amazon-desenvolvedor-de-software/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Amazon busca um Desenvolvedor de Software Mid Level para integrar o time de IES Latech Latam em Belo Horizonte. Você atuará no desenvolvimento de soluções robustas e escaláveis utilizando múltiplas linguagens de programação e tecnologias cloud.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações de software em ambiente de produção\u003c/li\u003e\u003cli\u003eColaborar com times multidisciplinares em projetos de infraestrutura e serviços web\u003c/li\u003e\u003cli\u003eImplementar soluções seguindo princípios de OOP e boas práticas de código\u003c/li\u003e\u003cli\u003eParticipar de ciclos de desenvolvimento ágil (Scrum, Kanban)\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência profissional em desenvolvimento de software (Mid Level)\u003c/li\u003e\u003cli\u003eProficiência em uma ou mais linguagens: Java, Kotlin, Python, Go, C/C++ ou JavaScript\u003c/li\u003e\u003cli\u003eConhecimento em banco de dados e serviços web\u003c/li\u003e\u003cli\u003eExperiência com Linux/UNIX\u003c/li\u003e\u003cli\u003eFamiliaridade com metodologias ágeis (Scrum, Kanban, XP)\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com AWS e infraestrutura cloud\u003c/li\u003e\u003cli\u003eConhecimento em Clojure ou outras linguagens funcionais\u003c/li\u003e\u003cli\u003eExperiência com RUP ou outros processos de engenharia de software\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor de Software"},{"content":"Sobre a vagaBuscamos um Engineering Manager experiente em Full Stack e Front End para liderar e desenvolver equipes de engenharia focadas em soluções de IA. Você será responsável por orientar arquitetura técnica, mentoria de engenheiros e entrega de produtos de alta qualidade.\nResponsabilidadesLiderar e desenvolver equipes de engenheiros Full Stack e Front EndDefinir e implementar arquitetura técnica para soluções de IAMentoriar engenheiros e promover crescimento técnicoColaborar com stakeholders para alinhamento de requisitos e roadmapGarantir qualidade de código e boas práticas de desenvolvimentoImplementar e manter pipelines de CI/CD eficientesRequisitosExperiência comprovada como Engineering Manager ou Tech LeadForte background em TypeScript, React e JavaScriptConhecimento de Kotlin, C# ou ScalaExperiência com GraphQL, REST e WebSocketsFamiliaridade com arquiteturas de micro-frontendsExcelentes habilidades de liderança e comunicaçãoExperiência em ambientes ágeis e metodologias modernasDiferenciaisExperiência anterior com IA e machine learningConhecimento de SSR (Server-Side Rendering)Histórico de crescimento de times de engenhariaExperiência em startups ou ambientes de rápido crescimento ","permalink":"https://kotlin.dev.br/vagas/74uvgd1d8d8tyh0p-agoda-engineering-manager-full-stack-front-end-ia/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Engineering Manager experiente em Full Stack e Front End para liderar e desenvolver equipes de engenharia focadas em soluções de IA. Você será responsável por orientar arquitetura técnica, mentoria de engenheiros e entrega de produtos de alta qualidade.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLiderar e desenvolver equipes de engenheiros Full Stack e Front End\u003c/li\u003e\u003cli\u003eDefinir e implementar arquitetura técnica para soluções de IA\u003c/li\u003e\u003cli\u003eMentoriar engenheiros e promover crescimento técnico\u003c/li\u003e\u003cli\u003eColaborar com stakeholders para alinhamento de requisitos e roadmap\u003c/li\u003e\u003cli\u003eGarantir qualidade de código e boas práticas de desenvolvimento\u003c/li\u003e\u003cli\u003eImplementar e manter pipelines de CI/CD eficientes\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência comprovada como Engineering Manager ou Tech Lead\u003c/li\u003e\u003cli\u003eForte background em TypeScript, React e JavaScript\u003c/li\u003e\u003cli\u003eConhecimento de Kotlin, C# ou Scala\u003c/li\u003e\u003cli\u003eExperiência com GraphQL, REST e WebSockets\u003c/li\u003e\u003cli\u003eFamiliaridade com arquiteturas de micro-frontends\u003c/li\u003e\u003cli\u003eExcelentes habilidades de liderança e comunicação\u003c/li\u003e\u003cli\u003eExperiência em ambientes ágeis e metodologias modernas\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência anterior com IA e machine learning\u003c/li\u003e\u003cli\u003eConhecimento de SSR (Server-Side Rendering)\u003c/li\u003e\u003cli\u003eHistórico de crescimento de times de engenharia\u003c/li\u003e\u003cli\u003eExperiência em startups ou ambientes de rápido crescimento\u003c/li\u003e\u003c/ul\u003e","title":"Engineering Manager Full Stack \u0026 Front End (IA)"},{"content":"Sobre a vaga Buscamos uma Pessoa Desenvolvedora Backend Pleno para integrar o time de CRM Engineering do C6 Bank. Você trabalharará com tecnologias modernas em um ambiente de microsserviços, desenvolvendo soluções robustas para o gerenciamento de relacionamento com clientes.\nResponsabilidades Desenvolver e manter serviços backend em Java/Kotlin usando Spring Boot Trabalhar com arquitetura de microsserviços Integração com plataformas de CRM e Marketing Cloud Salesforce Otimizar e gerenciar bancos de dados (PostgreSQL, MongoDB, Cassandra) Implementar automações e processos de RPA quando necessário Requisitos Experiência sólida com Java/Kotlin Conhecimento em Spring Boot Familiaridade com microsserviços Experiência com PostgreSQL, MongoDB ou Cassandra Nível pleno de desenvolvimento Diferenciais Conhecimento em Salesforce e Marketing Cloud Experiência com RPA e automação de processos Familiaridade com URA e sistemas de bot ","permalink":"https://kotlin.dev.br/vagas/yoluks1xhu6tlzxv-c6-bank-pessoa-desenvolvedora-backend-pleno-java-kotlin-crm-eng/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\n\u003cp\u003eBuscamos uma Pessoa Desenvolvedora Backend Pleno para integrar o time de CRM Engineering do C6 Bank. Você trabalharará com tecnologias modernas em um ambiente de microsserviços, desenvolvendo soluções robustas para o gerenciamento de relacionamento com clientes.\u003c/p\u003e\n\u003ch3\u003eResponsabilidades\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eDesenvolver e manter serviços backend em Java/Kotlin usando Spring Boot\u003c/li\u003e\n\u003cli\u003eTrabalhar com arquitetura de microsserviços\u003c/li\u003e\n\u003cli\u003eIntegração com plataformas de CRM e Marketing Cloud Salesforce\u003c/li\u003e\n\u003cli\u003eOtimizar e gerenciar bancos de dados (PostgreSQL, MongoDB, Cassandra)\u003c/li\u003e\n\u003cli\u003eImplementar automações e processos de RPA quando necessário\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003eRequisitos\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eExperiência sólida com Java/Kotlin\u003c/li\u003e\n\u003cli\u003eConhecimento em Spring Boot\u003c/li\u003e\n\u003cli\u003eFamiliaridade com microsserviços\u003c/li\u003e\n\u003cli\u003eExperiência com PostgreSQL, MongoDB ou Cassandra\u003c/li\u003e\n\u003cli\u003eNível pleno de desenvolvimento\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003eDiferenciais\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eConhecimento em Salesforce e Marketing Cloud\u003c/li\u003e\n\u003cli\u003eExperiência com RPA e automação de processos\u003c/li\u003e\n\u003cli\u003eFamiliaridade com URA e sistemas de bot\u003c/li\u003e\n\u003c/ul\u003e","title":"Pessoa Desenvolvedora Backend Pleno Java/Kotlin - CRM Engineering"},{"content":"Sobre a vagaProcuramos um Senior Android Mobile Developer experiente em Kotlin para se juntar ao time de desenvolvimento da CI\u0026T. Você trabalhará remotamente desenvolvendo e mantendo aplicações Android de alta qualidade.\nResponsabilidadesDesenvolver e manter aplicações Android utilizando Kotlin e Jetpack ComposeImplementar arquitetura MVVM em projetos mobileColaborar com o time em processos de CI/CDGarantir qualidade de código através de testes e análise estática com SonarOtimizar e depurar aplicações para melhor desempenhoParticipar de code reviews e compartilhar conhecimento técnicoRequisitosExperiência sênior comprovada em desenvolvimento AndroidProficiência em KotlinConhecimento sólido em Jetpack Compose e/ou XML layoutsExperiência com arquitetura MVVMFamiliares com integração FirebaseConhecimento em CI/CDExperiência com testes automatizadosDiferenciaisExperiência com BrowserStack para testesConhecimento em Sonar e qualidade de códigoContribuições open sourceExperiência com múltiplos devices e versões Android ","permalink":"https://kotlin.dev.br/vagas/zkxzidwyd7ddhwj2-ci-t-senior-android-mobile-developer/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eProcuramos um Senior Android Mobile Developer experiente em Kotlin para se juntar ao time de desenvolvimento da CI\u0026T. Você trabalhará remotamente desenvolvendo e mantendo aplicações Android de alta qualidade.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android utilizando Kotlin e Jetpack Compose\u003c/li\u003e\u003cli\u003eImplementar arquitetura MVVM em projetos mobile\u003c/li\u003e\u003cli\u003eColaborar com o time em processos de CI/CD\u003c/li\u003e\u003cli\u003eGarantir qualidade de código através de testes e análise estática com Sonar\u003c/li\u003e\u003cli\u003eOtimizar e depurar aplicações para melhor desempenho\u003c/li\u003e\u003cli\u003eParticipar de code reviews e compartilhar conhecimento técnico\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior comprovada em desenvolvimento Android\u003c/li\u003e\u003cli\u003eProficiência em Kotlin\u003c/li\u003e\u003cli\u003eConhecimento sólido em Jetpack Compose e/ou XML layouts\u003c/li\u003e\u003cli\u003eExperiência com arquitetura MVVM\u003c/li\u003e\u003cli\u003eFamiliares com integração Firebase\u003c/li\u003e\u003cli\u003eConhecimento em CI/CD\u003c/li\u003e\u003cli\u003eExperiência com testes automatizados\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com BrowserStack para testes\u003c/li\u003e\u003cli\u003eConhecimento em Sonar e qualidade de código\u003c/li\u003e\u003cli\u003eContribuições open source\u003c/li\u003e\u003cli\u003eExperiência com múltiplos devices e versões Android\u003c/li\u003e\u003c/ul\u003e","title":"Senior Android Mobile Developer"},{"content":"Mudar o banco local de um app Android parece simples enquanto o produto ainda está no emulador. Em produção, porém, cada usuário carrega uma versão diferente do schema no próprio aparelho. Alguns atualizaram ontem, outros ficaram meses sem abrir o app, outros têm dados criados offline e ainda não sincronizados. É por isso que migrations do Room com Kotlin são uma parte crítica da engenharia Android, não um detalhe burocrático de version = 2.\nO Room ajuda bastante porque valida queries em tempo de compilação, gera código para DAOs e oferece suporte a migrations automáticas e manuais. Mas ele não adivinha intenção de produto. Renomear uma coluna, dividir uma tabela, criar índice, mudar tipo de campo ou preservar dados pendentes exige disciplina. Este guia mostra um caminho prático para evoluir schema com segurança em apps Android Kotlin em 2026.\nSe você ainda está montando a base, comece pelo tutorial de Room Database com Kotlin, pela arquitetura Android offline-first com Kotlin e pelo guia de testes Android com Compose e Maestro. Migrations ficam muito mais previsíveis quando banco, sincronização e testes já têm responsabilidades claras.\nQuando uma migration é necessária? Toda mudança estrutural no banco local precisa de uma estratégia de migration. Exemplos comuns:\nadicionar uma coluna em uma tabela existente; renomear tabela ou coluna; criar índice para uma query lenta; mudar relacionamento entre entidades; dividir uma entidade grande em duas tabelas; alterar NOT NULL, valor padrão ou tipo de dado; criar tabela para fila de sincronização offline; remover campos antigos depois de uma mudança de produto. Mudanças apenas no código Kotlin, como renomear uma propriedade mantendo @ColumnInfo(name = \u0026quot;campo_antigo\u0026quot;), podem não mudar o schema. Mas qualquer alteração no SQL final precisa ser tratada como evolução de dados.\nExporte o schema desde o começo O primeiro hábito saudável é manter exportSchema = true e versionar os arquivos JSON gerados pelo Room. Eles são a memória formal do banco: permitem comparar versões, testar migrations e entender como o app chegou ao estado atual.\n@Database( entities = [TarefaEntity::class, ProjetoEntity::class], version = 3, exportSchema = true, ) abstract class AppDatabase : RoomDatabase() { abstract fun tarefaDao(): TarefaDao abstract fun projetoDao(): ProjetoDao } No Gradle Kotlin DSL, a configuração moderna aponta o diretório de schemas:\nandroid { defaultConfig { javaCompileOptions { annotationProcessorOptions { arguments += mapOf( \u0026#34;room.schemaLocation\u0026#34; to \u0026#34;$projectDir/schemas\u0026#34;, \u0026#34;room.incremental\u0026#34; to \u0026#34;true\u0026#34;, ) } } } } Em projetos com KSP, configure o argumento no bloco apropriado:\nksp { arg(\u0026#34;room.schemaLocation\u0026#34;, \u0026#34;$projectDir/schemas\u0026#34;) arg(\u0026#34;room.incremental\u0026#34;, \u0026#34;true\u0026#34;) } Versione esses JSONs no Git. Sem eles, você perde uma das melhores proteções contra migrations quebradas.\nAutoMigration para mudanças simples Para mudanças previsíveis, o Room consegue gerar migrations automáticas. Adicionar uma coluna com valor padrão, por exemplo, costuma ser um bom caso.\n@Entity(tableName = \u0026#34;tarefas\u0026#34;) data class TarefaEntity( @PrimaryKey val id: Long, val titulo: String, val concluida: Boolean, val prioridade: Int = 0, ) @Database( entities = [TarefaEntity::class], version = 2, autoMigrations = [ AutoMigration(from = 1, to = 2), ], exportSchema = true, ) abstract class AppDatabase : RoomDatabase() AutoMigration é ótima quando a intenção é clara e o Room consegue inferir o SQL sem ambiguidade. Ela não deve ser usada como desculpa para não revisar o schema. Leia o diff do JSON gerado e rode teste de migration.\nQuando há renome, remoção ou mudança ambígua, declare uma especificação:\n@RenameColumn( tableName = \u0026#34;tarefas\u0026#34;, fromColumnName = \u0026#34;nome\u0026#34;, toColumnName = \u0026#34;titulo\u0026#34;, ) class Migration1To2Spec : AutoMigrationSpec E conecte no banco:\n@Database( entities = [TarefaEntity::class], version = 2, autoMigrations = [ AutoMigration(from = 1, to = 2, spec = Migration1To2Spec::class), ], exportSchema = true, ) abstract class AppDatabase : RoomDatabase() Migration manual para cenários de produto Migrations manuais continuam essenciais quando a mudança envolve transformação real de dados. Imagine que o app tinha status como texto livre e agora quer separar concluida e arquivada.\nval MIGRATION_2_3 = object : Migration(2, 3) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL(\u0026#34;ALTER TABLE tarefas ADD COLUMN concluida INTEGER NOT NULL DEFAULT 0\u0026#34;) db.execSQL(\u0026#34;ALTER TABLE tarefas ADD COLUMN arquivada INTEGER NOT NULL DEFAULT 0\u0026#34;) db.execSQL(\u0026#34;\u0026#34;\u0026#34; UPDATE tarefas SET concluida = 1 WHERE status = \u0026#39;done\u0026#39; OR status = \u0026#39;concluida\u0026#39; \u0026#34;\u0026#34;\u0026#34;.trimIndent()) db.execSQL(\u0026#34;\u0026#34;\u0026#34; UPDATE tarefas SET arquivada = 1 WHERE status = \u0026#39;archived\u0026#39; OR status = \u0026#39;arquivada\u0026#39; \u0026#34;\u0026#34;\u0026#34;.trimIndent()) } } Depois registre no builder:\nRoom.databaseBuilder(context, AppDatabase::class.java, \u0026#34;app.db\u0026#34;) .addMigrations(MIGRATION_2_3) .build() Esse tipo de migration merece revisão cuidadosa. Pense em dados nulos, valores inesperados, usuários que pulam versões e registros criados offline. Em um app offline-first, nunca apague campos de controle de sincronização sem garantir que operações pendentes foram preservadas ou migradas.\nTestando migrations com MigrationTestHelper A regra mais importante: migration que não foi testada é aposta. O Room oferece MigrationTestHelper para criar um banco na versão antiga, inserir dados e validar a chegada na versão nova.\n@RunWith(AndroidJUnit4::class) class AppDatabaseMigrationTest { @get:Rule val helper = MigrationTestHelper( InstrumentationRegistry.getInstrumentation(), AppDatabase::class.java, ) @Test fun migrate2To3_preservaTarefasConcluidas() { helper.createDatabase(\u0026#34;test.db\u0026#34;, 2).apply { execSQL(\u0026#34;\u0026#34;\u0026#34; INSERT INTO tarefas (id, titulo, status) VALUES (1, \u0026#39;Enviar relatório\u0026#39;, \u0026#39;done\u0026#39;) \u0026#34;\u0026#34;\u0026#34;.trimIndent()) close() } val db = helper.runMigrationsAndValidate( \u0026#34;test.db\u0026#34;, 3, true, MIGRATION_2_3, ) val cursor = db.query(\u0026#34;SELECT concluida, arquivada FROM tarefas WHERE id = 1\u0026#34;) cursor.moveToFirst() assertThat(cursor.getInt(0)).isEqualTo(1) assertThat(cursor.getInt(1)).isEqualTo(0) cursor.close() } } Teste pelo menos o caminho da versão imediatamente anterior. Em apps com muitos usuários, também vale testar saltos maiores, como 1 para 4, porque nem todo mundo instala todas as versões intermediárias.\nCuidados com fallback destrutivo fallbackToDestructiveMigration() apaga e recria o banco quando a migration não existe. Isso pode parecer prático no desenvolvimento, mas em produção é perigoso. Se o banco tem favoritos, rascunhos, histórico, cache caro ou operações pendentes, destruir o banco vira perda de dados.\nUse fallback destrutivo apenas em bases descartáveis, protótipos ou ambientes internos. Para produção, prefira falhar em teste e corrigir a migration antes do release.\nSe existe uma tabela realmente descartável, isole esse dado. Nem todo cache precisa viver no mesmo banco que guarda estado importante do usuário.\nChecklist antes do release Antes de publicar uma versão que muda o schema, revise:\nversion do banco foi incrementada; schemas JSON foram gerados e versionados; migration cobre todos os caminhos necessários; dados existentes são preservados ou descartados de forma intencional; índices foram criados para queries novas ou mais pesadas; migrations rodam em teste instrumentado; saltos de versão relevantes foram testados; fallbackToDestructiveMigration() não está escondendo perda de dados; o app abre uma tela real após a migration; métricas e logs conseguem distinguir erro de migration de erro de rede. Para apps com WorkManager, DataStore e sincronização em background, pense também na ordem de inicialização. Não deixe um worker antigo tentar escrever em uma tabela que acabou de ser remodelada sem passar pelo novo código de repository.\nComo pensar em migrations no dia a dia A melhor migration é pequena, explícita e fácil de revisar. Evite acumular cinco mudanças de banco em um único release. Quando a mudança de produto for grande, quebre em etapas: adicionar nova coluna, preencher dados, passar leitura para o novo campo, remover o antigo depois de algumas versões.\nTambém vale tratar migration como parte do design da feature. Se a tarefa do sprint diz “adicionar favoritos offline”, ela deveria incluir entidade, DAO, sync, UI e migration. Deixar banco para o final aumenta a chance de quebrar usuários existentes.\nMigrations bem feitas raramente aparecem para o usuário. Esse é o objetivo. O app atualiza, abre normalmente e os dados continuam lá. Para o time, porém, elas deixam um rastro claro no Git, nos schemas e nos testes. Esse rastro é o que permite evoluir um app Android Kotlin por anos sem medo de tocar no banco local.\nSe você quer consolidar a trilha, estude também Paging 3 com Kotlin e Compose, segurança de dados locais no Android e KSP em Kotlin. Para comparar outras abordagens de persistência tipada, veja como o ecossistema irmão de Rust usa SQLx e Diesel em projetos com banco relacional.\nRoom precisa de migration para adicionar coluna? Sim, se a coluna muda o schema da tabela. Para uma coluna nova simples com valor padrão, AutoMigration costuma resolver bem. Ainda assim, gere schema, revise o diff e teste a migration.\nPosso usar fallbackToDestructiveMigration em produção? Evite. Ele apaga e recria o banco quando falta migration. Em produção, isso pode perder favoritos, rascunhos, cache importante e operações offline pendentes.\nPreciso testar migrations antigas? Sim. Teste pelo menos a versão anterior para a atual. Se o app tem muitos usuários que demoram a atualizar, teste saltos maiores, como versão 1 para 4.\nAutoMigration substitui migration manual? Não. AutoMigration cobre mudanças simples ou explicitamente anotadas. Transformações de dados, regras de produto, tabelas temporárias e preservação de estados offline ainda pedem migrations manuais.\n","permalink":"https://kotlin.dev.br/blog/migrations-room-android-kotlin-2026/","summary":"\u003cp\u003eMudar o banco local de um app Android parece simples enquanto o produto ainda está no emulador. Em produção, porém, cada usuário carrega uma versão diferente do schema no próprio aparelho. Alguns atualizaram ontem, outros ficaram meses sem abrir o app, outros têm dados criados offline e ainda não sincronizados. É por isso que \u003cstrong\u003emigrations do Room com Kotlin\u003c/strong\u003e são uma parte crítica da engenharia Android, não um detalhe burocrático de \u003ccode\u003eversion = 2\u003c/code\u003e.\u003c/p\u003e","title":"Migrations do Room no Android com Kotlin em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA SumUp busca um Backend Engineer Sênior experiente em Kotlin e Java para integrar seu time de engenharia. Você trabalhará no design e implementação de sistemas de backend escaláveis, utilizando tecnologias modernas na nuvem.\nResponsabilidadesArquitetar e desenvolver soluções backend robustas em Kotlin/JavaTrabalhar com infraestrutura AWS e otimizar performance de sistemasColaborar com times multidisciplinares para entregar funcionalidades de alto impactoContribuir para melhorias de código e práticas de engenhariaRequisitosExperiência sênior em desenvolvimento backend com Kotlin ou JavaConhecimento sólido de AWS e arquitetura em nuvemExperiência com bancos de dados relacionaisForte compreensão de design de sistemas e escalabilidadeBenefíciosAmbiente híbrido flexívelOportunidade de trabalhar em diferentes localizações ","permalink":"https://kotlin.dev.br/vagas/wbkrjw70fisd8l96-sumup-backend-engineer-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA SumUp busca um Backend Engineer Sênior experiente em Kotlin e Java para integrar seu time de engenharia. Você trabalhará no design e implementação de sistemas de backend escaláveis, utilizando tecnologias modernas na nuvem.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eArquitetar e desenvolver soluções backend robustas em Kotlin/Java\u003c/li\u003e\u003cli\u003eTrabalhar com infraestrutura AWS e otimizar performance de sistemas\u003c/li\u003e\u003cli\u003eColaborar com times multidisciplinares para entregar funcionalidades de alto impacto\u003c/li\u003e\u003cli\u003eContribuir para melhorias de código e práticas de engenharia\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento backend com Kotlin ou Java\u003c/li\u003e\u003cli\u003eConhecimento sólido de AWS e arquitetura em nuvem\u003c/li\u003e\u003cli\u003eExperiência com bancos de dados relacionais\u003c/li\u003e\u003cli\u003eForte compreensão de design de sistemas e escalabilidade\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eBenefícios\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAmbiente híbrido flexível\u003c/li\u003e\u003cli\u003eOportunidade de trabalhar em diferentes localizações\u003c/li\u003e\u003c/ul\u003e","title":"Backend Engineer Sênior"},{"content":"Sobre a vagaA CI\u0026T busca um desenvolvedor Kotlin/Android/Node.js de nível sênior para integrar seu time remoto. Você desenvolverá soluções fullstack com foco em qualidade, performance e boas práticas de engenharia.\nResponsabilidadesDesenvolver aplicações Android em Kotlin com arquitetura MVVMCriar e manter APIs backend com Node.jsImplementar pipelines CI/CD e automatizar processosColaborar com equipes cross-funcionaisGarantir qualidade de código através de testes e análise com SonarRequisitosExperiência sólida com Kotlin e desenvolvimento AndroidConhecimento em Node.js e Next.jsFamiliaridade com SQL e NoSQLExperiência com CI/CD e ferramentas de qualidade (Sonar)Inglês fluente para comunicação com times globaisDiferenciaisExperiência com arquitetura MVVMConhecimento em DevOps e containerizaçãoContribuições em projetos open source ","permalink":"https://kotlin.dev.br/vagas/hb7engdqls2enzst-ci-t-desenvolvedor-kotlin-android-node-js-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T busca um desenvolvedor Kotlin/Android/Node.js de nível sênior para integrar seu time remoto. Você desenvolverá soluções fullstack com foco em qualidade, performance e boas práticas de engenharia.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver aplicações Android em Kotlin com arquitetura MVVM\u003c/li\u003e\u003cli\u003eCriar e manter APIs backend com Node.js\u003c/li\u003e\u003cli\u003eImplementar pipelines CI/CD e automatizar processos\u003c/li\u003e\u003cli\u003eColaborar com equipes cross-funcionais\u003c/li\u003e\u003cli\u003eGarantir qualidade de código através de testes e análise com Sonar\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sólida com Kotlin e desenvolvimento Android\u003c/li\u003e\u003cli\u003eConhecimento em Node.js e Next.js\u003c/li\u003e\u003cli\u003eFamiliaridade com SQL e NoSQL\u003c/li\u003e\u003cli\u003eExperiência com CI/CD e ferramentas de qualidade (Sonar)\u003c/li\u003e\u003cli\u003eInglês fluente para comunicação com times globais\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com arquitetura MVVM\u003c/li\u003e\u003cli\u003eConhecimento em DevOps e containerização\u003c/li\u003e\u003cli\u003eContribuições em projetos open source\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Kotlin/Android/Node.js Sênior"},{"content":"Sobre a vagaA Mindera busca uma pessoa Engenheira Backend Java Sênior para atuação remota em times distribuídos. A vaga requer 8+ anos de experiência e envolve desenvolvimento backend com Java, Kotlin e Spring Boot.\nResponsabilidadesDesenvolver e manter serviços backend escaláveis.Trabalhar com arquitetura de microsserviços, mensageria e APIs.Colaborar com times de engenharia em práticas de qualidade, automação e entrega contínua.Aplicar TDD e boas práticas de engenharia de software.Requisitos8+ anos de experiência em engenharia backend.Experiência sólida com Java e Spring Boot.Conhecimento de Kotlin em ambientes backend.Experiência com Kafka, Kubernetes, Terraform e Azure.Vivência com Git, pipelines de CI/CD e práticas de TDD.Conhecimento de GraphQL Federation.LocalizaçãoVaga remota, aberta para profissionais em Casablanca, Porto, Aveiro, Coimbra, Leicester, San Diego, San Francisco, Chennai, Bengaluru, Cluj-Napoca, Blumenau ou Austrália.\n","permalink":"https://kotlin.dev.br/vagas/ki7vvw5m8kbw1wqa-mindera-engenheiro-backend-java-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Mindera busca uma pessoa Engenheira Backend Java Sênior para atuação remota em times distribuídos. A vaga requer 8+ anos de experiência e envolve desenvolvimento backend com Java, Kotlin e Spring Boot.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend escaláveis.\u003c/li\u003e\u003cli\u003eTrabalhar com arquitetura de microsserviços, mensageria e APIs.\u003c/li\u003e\u003cli\u003eColaborar com times de engenharia em práticas de qualidade, automação e entrega contínua.\u003c/li\u003e\u003cli\u003eAplicar TDD e boas práticas de engenharia de software.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003e8+ anos de experiência em engenharia backend.\u003c/li\u003e\u003cli\u003eExperiência sólida com Java e Spring Boot.\u003c/li\u003e\u003cli\u003eConhecimento de Kotlin em ambientes backend.\u003c/li\u003e\u003cli\u003eExperiência com Kafka, Kubernetes, Terraform e Azure.\u003c/li\u003e\u003cli\u003eVivência com Git, pipelines de CI/CD e práticas de TDD.\u003c/li\u003e\u003cli\u003eConhecimento de GraphQL Federation.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocalização\u003c/h3\u003e\u003cp\u003eVaga remota, aberta para profissionais em Casablanca, Porto, Aveiro, Coimbra, Leicester, San Diego, San Francisco, Chennai, Bengaluru, Cluj-Napoca, Blumenau ou Austrália.\u003c/p\u003e","title":"Engenheiro Backend Java Sênior"},{"content":"Sobre a vagaBuscamos um Senior Backend Software Engineer para integrar nosso time de plataforma. Você trabalhará com tecnologias modernas de cloud computing, arquiteturas de microserviços e bancos de dados escaláveis, contribuindo para soluções que impactam milhões de usuários globalmente.\nResponsabilidadesProjetar e implementar serviços backend escaláveis utilizando Kotlin, Java e outras linguagensArquitetar soluções em ambiente cloud (AWS, GCP)Desenvolver APIs RESTful e microserviçosOtimizar performance e escalabilidade de sistemasColaborar com times multidisciplinaresContribuir para melhoria contínua de práticas de engenhariaRequisitosExperiência sênior em desenvolvimento backendProficiência em Kotlin e/ou JavaConhecimento sólido em arquitetura de microserviçosExperiência com AWS ou GCPExpertise em bancos de dados relacionais (PostgreSQL, MySQL) e NoSQL (DynamoDB)Familiarity with RESTful web servicesStrong problem-solving skillsDiferenciaisExperiência com Go, Ruby ou C++Conhecimento de arquiteturas serverlessContribuições open source ","permalink":"https://kotlin.dev.br/vagas/4i9olsdesb87pff9-wellhub-senior-backend-software-engineer/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Senior Backend Software Engineer para integrar nosso time de plataforma. Você trabalhará com tecnologias modernas de cloud computing, arquiteturas de microserviços e bancos de dados escaláveis, contribuindo para soluções que impactam milhões de usuários globalmente.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eProjetar e implementar serviços backend escaláveis utilizando Kotlin, Java e outras linguagens\u003c/li\u003e\u003cli\u003eArquitetar soluções em ambiente cloud (AWS, GCP)\u003c/li\u003e\u003cli\u003eDesenvolver APIs RESTful e microserviços\u003c/li\u003e\u003cli\u003eOtimizar performance e escalabilidade de sistemas\u003c/li\u003e\u003cli\u003eColaborar com times multidisciplinares\u003c/li\u003e\u003cli\u003eContribuir para melhoria contínua de práticas de engenharia\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento backend\u003c/li\u003e\u003cli\u003eProficiência em Kotlin e/ou Java\u003c/li\u003e\u003cli\u003eConhecimento sólido em arquitetura de microserviços\u003c/li\u003e\u003cli\u003eExperiência com AWS ou GCP\u003c/li\u003e\u003cli\u003eExpertise em bancos de dados relacionais (PostgreSQL, MySQL) e NoSQL (DynamoDB)\u003c/li\u003e\u003cli\u003eFamiliarity with RESTful web services\u003c/li\u003e\u003cli\u003eStrong problem-solving skills\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Go, Ruby ou C++\u003c/li\u003e\u003cli\u003eConhecimento de arquiteturas serverless\u003c/li\u003e\u003cli\u003eContribuições open source\u003c/li\u003e\u003c/ul\u003e","title":"Senior Backend Software Engineer"},{"content":"Sobre a vagaBuscamos um Senior Kotlin Developer para integrar nosso time de desenvolvimento mobile. Você trabalhará com tecnologias modernas como Jetpack Compose, Kotlin Multiplatform e arquiteturas reativas.\nResponsabilidadesDesenvolver e manter aplicações Android com KotlinImplementar interfaces com Jetpack ComposeArquitetar soluções usando Kotlin Multiplatform (KMM)Aplicar padrões MVVM e MVI em projetosParticipar de code reviews e mentoria técnicaIntegrar APIs RESTful com RetrofitRequisitosExperiência sênior em desenvolvimento KotlinDomínio de Jetpack Compose e Jetpack Architecture ComponentsConhecimento em Coroutines e Kotlin FlowExperiência com padrões MVVM, MVI e princípios SOLIDProficiência em testes unitários com JUnitExperiência com Git e controle de versãoConhecimento de FirebaseDiferenciaisExperiência com Kotlin Multiplatform (KMM)Familiaridade com Koin para injeção de dependênciaContribuições em projetos open source Kotlin ","permalink":"https://kotlin.dev.br/vagas/ez5bkvpx02ca68l4-ab-inbev-senior-kotlin-developer/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Senior Kotlin Developer para integrar nosso time de desenvolvimento mobile. Você trabalhará com tecnologias modernas como Jetpack Compose, Kotlin Multiplatform e arquiteturas reativas.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android com Kotlin\u003c/li\u003e\u003cli\u003eImplementar interfaces com Jetpack Compose\u003c/li\u003e\u003cli\u003eArquitetar soluções usando Kotlin Multiplatform (KMM)\u003c/li\u003e\u003cli\u003eAplicar padrões MVVM e MVI em projetos\u003c/li\u003e\u003cli\u003eParticipar de code reviews e mentoria técnica\u003c/li\u003e\u003cli\u003eIntegrar APIs RESTful com Retrofit\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Kotlin\u003c/li\u003e\u003cli\u003eDomínio de Jetpack Compose e Jetpack Architecture Components\u003c/li\u003e\u003cli\u003eConhecimento em Coroutines e Kotlin Flow\u003c/li\u003e\u003cli\u003eExperiência com padrões MVVM, MVI e princípios SOLID\u003c/li\u003e\u003cli\u003eProficiência em testes unitários com JUnit\u003c/li\u003e\u003cli\u003eExperiência com Git e controle de versão\u003c/li\u003e\u003cli\u003eConhecimento de Firebase\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin Multiplatform (KMM)\u003c/li\u003e\u003cli\u003eFamiliaridade com Koin para injeção de dependência\u003c/li\u003e\u003cli\u003eContribuições em projetos open source Kotlin\u003c/li\u003e\u003c/ul\u003e","title":"Senior Kotlin Developer"},{"content":"Sobre a vagaBuscamos um Desenvolvedor Kotlin Sênior para integrar nosso time de desenvolvimento mobile. Você atuará com tecnologias modernas de Android, liderando arquitetura de projetos e mentorando desenvolvedores junior.\nResponsabilidadesDesenvolver aplicações Android com Kotlin, Jetpack Compose e CoroutinesImplementar soluções com Kotlin Flow, Retrofit e RESTful APIsArquitetar aplicações seguindo padrões MVVM e MVIUtilizar Jetpack Architecture Components para construir aplicações robustasConfigurar e manter pipelines de CI/CDIntegrar Firebase para funcionalidades backendGerenciar dependências com KoinEscrever testes com JUnit e garantir qualidade de códigoColaborar com times via Git e boas práticas de versionamentoExplorar Kotlin Multiplatform para compartilhar código entre plataformasRequisitosExperiência sênior com Kotlin e desenvolvimento AndroidDomínio de Jetpack Compose e CoroutinesConhecimento em arquitetura de aplicações (MVVM, MVI)Experiência com testes unitários (JUnit)Familiaridade com CI/CD e automaçãoExcelente comunicação e capacidade de liderança técnicaDiferenciaisExperiência com Kotlin Multiplatform (KMM)Conhecimento em Firebase e integrações cloudContribuições em projetos open sourceExperiência mentorando desenvolvedores ","permalink":"https://kotlin.dev.br/vagas/zsc78doow527h16g-ab-inbev-senior-kotlin-developer/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Desenvolvedor Kotlin Sênior para integrar nosso time de desenvolvimento mobile. Você atuará com tecnologias modernas de Android, liderando arquitetura de projetos e mentorando desenvolvedores junior.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver aplicações Android com Kotlin, Jetpack Compose e Coroutines\u003c/li\u003e\u003cli\u003eImplementar soluções com Kotlin Flow, Retrofit e RESTful APIs\u003c/li\u003e\u003cli\u003eArquitetar aplicações seguindo padrões MVVM e MVI\u003c/li\u003e\u003cli\u003eUtilizar Jetpack Architecture Components para construir aplicações robustas\u003c/li\u003e\u003cli\u003eConfigurar e manter pipelines de CI/CD\u003c/li\u003e\u003cli\u003eIntegrar Firebase para funcionalidades backend\u003c/li\u003e\u003cli\u003eGerenciar dependências com Koin\u003c/li\u003e\u003cli\u003eEscrever testes com JUnit e garantir qualidade de código\u003c/li\u003e\u003cli\u003eColaborar com times via Git e boas práticas de versionamento\u003c/li\u003e\u003cli\u003eExplorar Kotlin Multiplatform para compartilhar código entre plataformas\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com Kotlin e desenvolvimento Android\u003c/li\u003e\u003cli\u003eDomínio de Jetpack Compose e Coroutines\u003c/li\u003e\u003cli\u003eConhecimento em arquitetura de aplicações (MVVM, MVI)\u003c/li\u003e\u003cli\u003eExperiência com testes unitários (JUnit)\u003c/li\u003e\u003cli\u003eFamiliaridade com CI/CD e automação\u003c/li\u003e\u003cli\u003eExcelente comunicação e capacidade de liderança técnica\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin Multiplatform (KMM)\u003c/li\u003e\u003cli\u003eConhecimento em Firebase e integrações cloud\u003c/li\u003e\u003cli\u003eContribuições em projetos open source\u003c/li\u003e\u003cli\u003eExperiência mentorando desenvolvedores\u003c/li\u003e\u003c/ul\u003e","title":"Senior Kotlin Developer"},{"content":"Sobre a vagaBuscamos um Senior Mobile Software Engineer experiente para desenvolver e manter aplicações móveis de alto impacto usando Kotlin e Android.\nResponsabilidadesDesenvolver e melhorar aplicações Android com KotlinImplementar interfaces modernas com Jetpack ComposeAplicar Clean Architecture, MVVM e princípios SOLIDColaborar com o time de produto e designRevisar código e mentorear desenvolvedores júnioresGarantir qualidade através de testes com Mockito e boas práticasRequisitosExperiência sênior com Kotlin e desenvolvimento AndroidDomínio de Jetpack Compose, Android Jetpack, AndroidXConhecimento de Room, Firebase, Hilt e NavigationExperiência com Clean Architecture e padrões MVVMForte compreensão de SOLID e boas práticasExperiência com versionamento Git, JIRA e metodologias KanbanDiferenciaisExperiência com analytics (Mixpanel)Histórico de contribuições em projetos open sourcePassado de impacto em aplicações com milhões de usuáriosBenefíciosTrabalho 100% remotoFlexibilidade de horárioAmbiente colaborativo e inovador ","permalink":"https://kotlin.dev.br/vagas/161xo6vq1woibyr0-neon-senior-mobile-software-engineer-kotlin-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Senior Mobile Software Engineer experiente para desenvolver e manter aplicações móveis de alto impacto usando Kotlin e Android.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e melhorar aplicações Android com Kotlin\u003c/li\u003e\u003cli\u003eImplementar interfaces modernas com Jetpack Compose\u003c/li\u003e\u003cli\u003eAplicar Clean Architecture, MVVM e princípios SOLID\u003c/li\u003e\u003cli\u003eColaborar com o time de produto e design\u003c/li\u003e\u003cli\u003eRevisar código e mentorear desenvolvedores júniores\u003c/li\u003e\u003cli\u003eGarantir qualidade através de testes com Mockito e boas práticas\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com Kotlin e desenvolvimento Android\u003c/li\u003e\u003cli\u003eDomínio de Jetpack Compose, Android Jetpack, AndroidX\u003c/li\u003e\u003cli\u003eConhecimento de Room, Firebase, Hilt e Navigation\u003c/li\u003e\u003cli\u003eExperiência com Clean Architecture e padrões MVVM\u003c/li\u003e\u003cli\u003eForte compreensão de SOLID e boas práticas\u003c/li\u003e\u003cli\u003eExperiência com versionamento Git, JIRA e metodologias Kanban\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com analytics (Mixpanel)\u003c/li\u003e\u003cli\u003eHistórico de contribuições em projetos open source\u003c/li\u003e\u003cli\u003ePassado de impacto em aplicações com milhões de usuários\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eBenefícios\u003c/h3\u003e\u003cul\u003e\u003cli\u003eTrabalho 100% remoto\u003c/li\u003e\u003cli\u003eFlexibilidade de horário\u003c/li\u003e\u003cli\u003eAmbiente colaborativo e inovador\u003c/li\u003e\u003c/ul\u003e","title":"Senior Mobile Software Engineer - Kotlin/Android"},{"content":"Sobre a vagaA Stone busca um Software Engineering Manager I para liderar times de engenharia de software. Você será responsável por orientar, desenvolver e motivar engenheiros, garantindo excelência técnica e entrega de valor.\nResponsabilidadesLiderar, mentorar e desenvolver engenheiros de softwareDefinir direção técnica e arquitetura de projetosGarantir qualidade de código, testes e práticas de desenvolvimentoColaborar com stakeholders para alinhar objetivos técnicos e de negócioMonitorar métricas de engenharia (DORA) e melhorar processosConduzir recrutamento e entrevistas técnicasRequisitosExperiência sênior em desenvolvimento de softwareExperiência comprovada em gestão de times técnicosConhecimento profundo em pelo menos uma das tecnologias: Kotlin, Golang, Elixir ou .NETFamiliaridade com Android, iOS ou desenvolvimento MultiplatformExperiência com CI/CD e métricas de engenharia (DORA)DiferenciaisExperiência com Kotlin Multiplatform (KMP) ou Compose Multiplatform (CMP)Background em startups ou empresas de rápido crescimentoConhecimento em múltiplas linguagens de programação ","permalink":"https://kotlin.dev.br/vagas/tlkhgg4qhj13sbtx-stone-software-engineering-manager-i/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Stone busca um Software Engineering Manager I para liderar times de engenharia de software. Você será responsável por orientar, desenvolver e motivar engenheiros, garantindo excelência técnica e entrega de valor.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLiderar, mentorar e desenvolver engenheiros de software\u003c/li\u003e\u003cli\u003eDefinir direção técnica e arquitetura de projetos\u003c/li\u003e\u003cli\u003eGarantir qualidade de código, testes e práticas de desenvolvimento\u003c/li\u003e\u003cli\u003eColaborar com stakeholders para alinhar objetivos técnicos e de negócio\u003c/li\u003e\u003cli\u003eMonitorar métricas de engenharia (DORA) e melhorar processos\u003c/li\u003e\u003cli\u003eConduzir recrutamento e entrevistas técnicas\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento de software\u003c/li\u003e\u003cli\u003eExperiência comprovada em gestão de times técnicos\u003c/li\u003e\u003cli\u003eConhecimento profundo em pelo menos uma das tecnologias: Kotlin, Golang, Elixir ou .NET\u003c/li\u003e\u003cli\u003eFamiliaridade com Android, iOS ou desenvolvimento Multiplatform\u003c/li\u003e\u003cli\u003eExperiência com CI/CD e métricas de engenharia (DORA)\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin Multiplatform (KMP) ou Compose Multiplatform (CMP)\u003c/li\u003e\u003cli\u003eBackground em startups ou empresas de rápido crescimento\u003c/li\u003e\u003cli\u003eConhecimento em múltiplas linguagens de programação\u003c/li\u003e\u003c/ul\u003e","title":"Software Engineering Manager I"},{"content":"Sobre a vagaA Stone procura um Software Engineering Manager I para liderar equipes de engenharia em um ambiente remoto. Você será responsável por orientar desenvolvedores, facilitar a colaboração e impulsionar a excelência técnica em projetos críticos.\nResponsabilidadesGerenciar e mentorar equipes de engenheiros de softwareFacilitar colaboração entre times e stakeholdersGarantir qualidade técnica e boas práticas de desenvolvimentoContribuir para o crescimento profissional da equipeParticipar de decisões arquiteturais e estratégicasRequisitosExperiência comprovada em gestão de equipes de engenhariaConhecimento técnico sólido em tecnologias backend e mobileProficiência em Kotlin ou linguagens relacionadasFamiliaridade com CI/CD e práticas DevOpsExcelentes habilidades de comunicação e liderançaDiferenciaisExperiência com Android, KMP ou Compose MultiplatformConhecimento em Golang, Elixir ou .NETHistórico de desenvolvimento de líderes técnicos ","permalink":"https://kotlin.dev.br/vagas/wc3lt3euqbxghac2-stone-software-engineering-manager-i/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Stone procura um Software Engineering Manager I para liderar equipes de engenharia em um ambiente remoto. Você será responsável por orientar desenvolvedores, facilitar a colaboração e impulsionar a excelência técnica em projetos críticos.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eGerenciar e mentorar equipes de engenheiros de software\u003c/li\u003e\u003cli\u003eFacilitar colaboração entre times e stakeholders\u003c/li\u003e\u003cli\u003eGarantir qualidade técnica e boas práticas de desenvolvimento\u003c/li\u003e\u003cli\u003eContribuir para o crescimento profissional da equipe\u003c/li\u003e\u003cli\u003eParticipar de decisões arquiteturais e estratégicas\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência comprovada em gestão de equipes de engenharia\u003c/li\u003e\u003cli\u003eConhecimento técnico sólido em tecnologias backend e mobile\u003c/li\u003e\u003cli\u003eProficiência em Kotlin ou linguagens relacionadas\u003c/li\u003e\u003cli\u003eFamiliaridade com CI/CD e práticas DevOps\u003c/li\u003e\u003cli\u003eExcelentes habilidades de comunicação e liderança\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Android, KMP ou Compose Multiplatform\u003c/li\u003e\u003cli\u003eConhecimento em Golang, Elixir ou .NET\u003c/li\u003e\u003cli\u003eHistórico de desenvolvimento de líderes técnicos\u003c/li\u003e\u003c/ul\u003e","title":"Software Engineering Manager I"},{"content":"Sobre a vagaBuscamos um Tech Lead experiente para liderar o desenvolvimento de soluções de tecnologia no segmento bancário. Você será responsável por arquitetura, qualidade técnica e mentoría de um time de engenheiros.\nResponsabilidadesDefinir e implementar arquitetura técnica de sistemas bancáriosLiderar e mentorar engenheiros de softwareGarantir qualidade, performance e segurança do códigoAvaliar e adotar novas tecnologiasColaborar com produto e stakeholders para soluções escaláveisRequisitos5+ anos de experiência em desenvolvimento backendSólida experiência com Kotlin e/ou JavaConhecimento de Spring Boot e ecossistema SpringExperiência com arquitetura de microsserviçosFamiliaridade com NoSQL (MongoDB, DynamoDB ou similar)Experiência com cloud (AWS, Azure ou GCP)Liderança técnica comprovadaDiferenciaisExperiência em sistemas financeiros ou bankingConhecimento de arquitetura de evento e CQRSCertificações em cloud ou arquitetura ","permalink":"https://kotlin.dev.br/vagas/tmjbxrliswci2a2n-btg-pactual-tech-lead-banking/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Tech Lead experiente para liderar o desenvolvimento de soluções de tecnologia no segmento bancário. Você será responsável por arquitetura, qualidade técnica e mentoría de um time de engenheiros.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDefinir e implementar arquitetura técnica de sistemas bancários\u003c/li\u003e\u003cli\u003eLiderar e mentorar engenheiros de software\u003c/li\u003e\u003cli\u003eGarantir qualidade, performance e segurança do código\u003c/li\u003e\u003cli\u003eAvaliar e adotar novas tecnologias\u003c/li\u003e\u003cli\u003eColaborar com produto e stakeholders para soluções escaláveis\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003e5+ anos de experiência em desenvolvimento backend\u003c/li\u003e\u003cli\u003eSólida experiência com Kotlin e/ou Java\u003c/li\u003e\u003cli\u003eConhecimento de Spring Boot e ecossistema Spring\u003c/li\u003e\u003cli\u003eExperiência com arquitetura de microsserviços\u003c/li\u003e\u003cli\u003eFamiliaridade com NoSQL (MongoDB, DynamoDB ou similar)\u003c/li\u003e\u003cli\u003eExperiência com cloud (AWS, Azure ou GCP)\u003c/li\u003e\u003cli\u003eLiderança técnica comprovada\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em sistemas financeiros ou banking\u003c/li\u003e\u003cli\u003eConhecimento de arquitetura de evento e CQRS\u003c/li\u003e\u003cli\u003eCertificações em cloud ou arquitetura\u003c/li\u003e\u003c/ul\u003e","title":"Tech Lead - Banking"},{"content":"O Android 16 torna impossível empurrar o problema de edge-to-edge para depois. Desde o Android 15, apps com targetSdk 35 já desenham por baixo das barras do sistema em muitos cenários. No Android 16, para apps mirando API 36, a rota de escape windowOptOutEdgeToEdgeEnforcement deixa de resolver o problema. Se a sua tela Compose ainda depende de statusBarColor, margens fixas ou padding(top = 24.dp), a migração para targetSdk = 36 pode revelar botões cobertos, listas cortadas, FAB colado na barra de navegação e campos de texto escondidos pelo teclado.\nA boa notícia: em Kotlin com Jetpack Compose, a solução costuma ser limpa quando o time trata WindowInsets como parte da arquitetura de UI. Edge-to-edge não significa deixar tudo atrás da barra do sistema. Significa permitir que o app use a janela inteira e aplicar espaçamentos conscientes onde o conteúdo precisa permanecer legível, clicável e acessível.\nSe você já acompanha nossos guias de Jetpack Compose, Navigation 3 no Android, Baseline Profiles e Macrobenchmark e testes Android com Compose e Maestro, este artigo fecha uma lacuna prática: preparar a UI para o comportamento visual que o Android moderno exige.\nO que muda no Android 16? O ponto central é simples: apps que miram Android 16 precisam assumir que o conteúdo pode ocupar a área por trás de status bar, navigation bar e display cutouts. Em versões anteriores, alguns times mantinham a aparência antiga com flags de opt-out. Essa estratégia fica frágil quando o app avança o targetSdk.\nNa prática, você deve revisar:\ntelas com Scaffold e barras superiores; listas em LazyColumn ou LazyVerticalGrid; botões fixos no rodapé; formulários com teclado aberto; bottom sheets, dialogs e overlays; telas com imagens hero ou mapas; navegação com predictive back; flows de login, checkout, perfil e detalhes. O erro mais comum é tratar insets como um ajuste cosmético. Eles são uma regra de layout. Se o app já usa Compose, estado de UI, coroutines e navegação declarativa, vale integrar insets ao mesmo nível de cuidado que você dá a temas, breakpoints e acessibilidade.\nConfigure o projeto para target SDK 36 Antes de ajustar UI, deixe claro onde o projeto está. Um exemplo mínimo de Gradle Kotlin DSL para um app Android moderno seria:\nplugins { id(\u0026#34;com.android.application\u0026#34;) kotlin(\u0026#34;android\u0026#34;) } android { namespace = \u0026#34;br.dev.kotlin.edge\u0026#34; compileSdk = 36 defaultConfig { applicationId = \u0026#34;br.dev.kotlin.edge\u0026#34; minSdk = 24 targetSdk = 36 versionCode = 1 versionName = \u0026#34;1.0\u0026#34; } buildFeatures { compose = true } } Não faça essa mudança como um commit isolado no fim da sprint. Atualizar targetSdk deve vir acompanhado de uma bateria de telas críticas, porque a regressão visual aparece em tempo de execução, não necessariamente no build.\nAtive edge-to-edge na Activity Em apps Compose, o ponto de entrada normalmente é a ComponentActivity. A recomendação moderna é ativar edge-to-edge cedo, antes de desenhar o conteúdo:\nimport android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() super.onCreate(savedInstanceState) setContent { KotlinBrasilTheme { AppRoot() } } } } Esse passo sozinho não resolve layout. Ele apenas coloca o app no modo certo. A partir daqui, cada tela precisa decidir quais áreas podem ser decorativas e quais áreas precisam de padding para não ficarem sob as barras do sistema.\nUse Scaffold com insets explícitos Um padrão seguro é deixar o Scaffold receber os insets corretos e propagar o padding para o conteúdo:\n@Composable fun FeedScreen() { Scaffold( topBar = { TopAppBar( title = { Text(\u0026#34;Artigos Kotlin\u0026#34;) } ) }, contentWindowInsets = WindowInsets.safeDrawing ) { innerPadding -\u0026gt; LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = innerPadding ) { items(artigos) { artigo -\u0026gt; ArtigoCard(artigo) } } } } WindowInsets.safeDrawing é um bom ponto de partida para telas em que todo conteúdo importante precisa ficar visível. Ele considera áreas onde desenho pode ser inseguro por causa de barras do sistema e cutouts.\nMas nem toda tela deve usar o mesmo comportamento. Uma tela com imagem de capa pode desenhar a imagem atrás da status bar e aplicar padding apenas ao título ou aos botões:\n@Composable fun DetalheArtigoScreen() { Box(Modifier.fillMaxSize()) { HeaderImage( modifier = Modifier .fillMaxWidth() .height(260.dp) ) Column( modifier = Modifier .fillMaxSize() .padding(WindowInsets.safeDrawing.asPaddingValues()) ) { BackButton() Spacer(Modifier.height(180.dp)) ArticleBody() } } } A diferença é intencional: decoração pode ocupar a borda; ação e texto precisam respeitar área segura.\nNão some padding duas vezes Um bug clássico em Compose é aplicar insets no Scaffold, depois aplicar statusBarsPadding() ou navigationBarsPadding() dentro do conteúdo e acabar com espaçamento duplicado.\nEvite misturar padrões sem necessidade:\n// Suspeito: pode duplicar padding dependendo da tela Scaffold(contentWindowInsets = WindowInsets.safeDrawing) { innerPadding -\u0026gt; Column( Modifier .padding(innerPadding) .statusBarsPadding() ) { Conteudo() } } Prefira um ponto de verdade por tela. Se o Scaffold controla o padding, passe innerPadding para a área rolável. Se a tela é customizada com Box, use WindowInsets.safeDrawing.asPaddingValues() manualmente. O time deve conseguir olhar a tela e responder: “quem é responsável pelos insets aqui?”.\nListas precisam de rodapé seguro Em apps reais, a maioria das regressões aparece em listas. O último item fica atrás da navigation bar, um botão flutuante cobre conteúdo ou o scroll não permite enxergar a ação final.\nUma LazyColumn com CTA fixo no rodapé precisa combinar insets com espaçamento extra:\n@Composable fun VagasKotlinScreen() { Box(Modifier.fillMaxSize()) { LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = PaddingValues( start = 16.dp, top = 16.dp, end = 16.dp, bottom = 96.dp ) ) { items(vagas) { vaga -\u0026gt; VagaCard(vaga) } } Button( onClick = { /* salvar alerta */ }, modifier = Modifier .align(Alignment.BottomCenter) .navigationBarsPadding() .padding(16.dp) .fillMaxWidth() ) { Text(\u0026#34;Criar alerta de vaga\u0026#34;) } } } Aqui, a lista ganha espaço para não terminar sob o botão, e o botão respeita a navigation bar. Em telas com FAB, a lógica é a mesma: o componente fixo deve ter padding de sistema, e a área rolável precisa de bottom padding suficiente para não ficar escondida.\nTeclado: imePadding não é opcional Formulários são outra fonte de dor. Edge-to-edge com teclado aberto exige tratar IME inset. Uma tela de login simples pode usar:\n@Composable fun LoginScreen() { Column( modifier = Modifier .fillMaxSize() .safeDrawingPadding() .imePadding() .verticalScroll(rememberScrollState()) .padding(24.dp), verticalArrangement = Arrangement.Center ) { Text(\u0026#34;Entrar\u0026#34;, style = MaterialTheme.typography.headlineMedium) Spacer(Modifier.height(24.dp)) OutlinedTextField( value = email, onValueChange = { email = it }, label = { Text(\u0026#34;E-mail\u0026#34;) }, modifier = Modifier.fillMaxWidth() ) Spacer(Modifier.height(12.dp)) OutlinedTextField( value = senha, onValueChange = { senha = it }, label = { Text(\u0026#34;Senha\u0026#34;) }, modifier = Modifier.fillMaxWidth() ) Spacer(Modifier.height(24.dp)) Button(onClick = ::entrar, modifier = Modifier.fillMaxWidth()) { Text(\u0026#34;Continuar\u0026#34;) } } } imePadding() desloca o conteúdo quando o teclado aparece. O verticalScroll garante que telas menores ainda consigam acessar o botão. Sem isso, a tela pode parecer correta em um Pixel grande e quebrar em aparelhos intermediários, tablets dobráveis ou layouts com fonte aumentada.\nTop bars e status bar transparente Com edge-to-edge, barras superiores devem parecer parte da UI, não uma faixa quebrada. Em Compose Material 3, TopAppBar funciona bem, mas você precisa decidir se ela terá cor sólida, translúcida ou se ficará sobre uma imagem.\nPara telas comuns:\nTopAppBar( title = { Text(\u0026#34;Configurações\u0026#34;) }, colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.surface ) ) Para hero visual, use contraste forte e teste legibilidade em modo claro, escuro e com imagem carregando lentamente. O problema não é só técnico; é de UX. Um ícone branco sobre imagem clara atrás da status bar vira bug de acessibilidade.\nCutouts e telas grandes Edge-to-edge também conversa com tablets, dobráveis e display cutouts. Não presuma que status bar fica sempre no topo ou que navigation bar fica sempre embaixo. Em landscape, foldables e janelas redimensionáveis, os insets podem mudar bastante.\nPor isso, evite constantes mágicas:\n// Frágil Modifier.padding(top = 24.dp, bottom = 48.dp) Prefira APIs de inset:\nModifier.windowInsetsPadding(WindowInsets.safeDrawing) E combine com layout adaptativo quando a tela crescer. Se o projeto usa duas colunas, navigation rail ou painel mestre-detalhe, revise também nossos conteúdos sobre Compose Multiplatform e Kotlin Multiplatform, porque a disciplina de layout responsivo é parecida: estado claro, áreas seguras e componentes que não dependem de um único tamanho de tela.\nComo testar sem depender do “olhômetro” A migração para edge-to-edge precisa de checklist. Um fluxo básico:\nrode o app em Android 15 e Android 16; teste navegação por gestos e por três botões; abra teclado em todos os formulários; aumente fonte e display size; teste landscape em telas críticas; capture screenshots antes/depois; rode Macrobenchmark ou testes de screenshot onde fizer sentido. Para Compose, testes automatizados podem validar se elementos existem e continuam clicáveis, mas screenshot tests ajudam a detectar corte visual. O artigo sobre Baseline Profiles e Macrobenchmark cobre a parte de medição de performance; para edge-to-edge, o foco é combinar essa disciplina com regressão visual e QA manual em aparelhos representativos.\nTambém vale revisar a pipeline. Se o time usa GitHub Actions, o guia de CI/CD para Kotlin ajuda a organizar checks por pull request. Para comparar com estratégias de validação em outras stacks mobile/backend, há paralelos úteis em automação e testes no ecossistema Python, especialmente na disciplina de separar teste rápido, teste visual e teste end-to-end.\nChecklist de migração Antes de subir targetSdk = 36 para produção, revise:\nenableEdgeToEdge() chamado na Activity principal; nenhum uso cego de padding fixo para status/navigation bar; Scaffold com contentWindowInsets definido conscientemente; listas com bottom padding suficiente; CTAs fixos com navigationBarsPadding(); formulários com imePadding() e scroll; telas com hero image testadas com contraste real; bottom sheets e dialogs revisados; screenshots em Android 15/16; QA com fonte aumentada; regressão de performance em telas críticas. Erros comuns O primeiro erro é achar que edge-to-edge é só “deixar transparente”. Transparência sem insets vira conteúdo ilegível.\nO segundo é corrigir tela por tela com números mágicos. Isso funciona até trocar aparelho, orientação ou modo de navegação.\nO terceiro é ignorar teclado. Muitas migrações parecem boas até o usuário editar um campo no fim da tela.\nO quarto é duplicar padding. Se a tela parece “baixa demais”, desconfie de Scaffold mais safeDrawingPadding() no mesmo eixo.\nO quinto é não envolver design e QA. Edge-to-edge muda densidade visual, hierarquia e contraste. Não é apenas uma tarefa de Android.\nConclusão Android 16 transforma edge-to-edge em requisito prático para apps Kotlin modernos. A migração não precisa ser traumática, mas precisa ser deliberada: ative o modo corretamente, escolha o responsável pelos insets em cada tela, trate listas e formulários como casos críticos e valide em dispositivos reais.\nPara times que já usam Compose, coroutines, Navigation 3 e CI/CD, essa é uma boa oportunidade de elevar a qualidade visual do app. Em vez de “consertar barra do sistema”, pense em uma UI que entende a janela inteira, protege conteúdo importante e aproveita melhor o espaço disponível.\nO resultado é um app mais atual, mais consistente e pronto para a próxima onda de aparelhos Android — de celulares compactos a dobráveis, tablets e janelas redimensionáveis.\n","permalink":"https://kotlin.dev.br/blog/android-16-edge-to-edge-compose-kotlin-2026/","summary":"\u003cp\u003eO Android 16 torna impossível empurrar o problema de \u003cstrong\u003eedge-to-edge\u003c/strong\u003e para depois. Desde o Android 15, apps com \u003ccode\u003etargetSdk\u003c/code\u003e 35 já desenham por baixo das barras do sistema em muitos cenários. No Android 16, para apps mirando API 36, a rota de escape \u003ccode\u003ewindowOptOutEdgeToEdgeEnforcement\u003c/code\u003e deixa de resolver o problema. Se a sua tela Compose ainda depende de \u003ccode\u003estatusBarColor\u003c/code\u003e, margens fixas ou \u003ccode\u003epadding(top = 24.dp)\u003c/code\u003e, a migração para \u003ccode\u003etargetSdk = 36\u003c/code\u003e pode revelar botões cobertos, listas cortadas, FAB colado na barra de navegação e campos de texto escondidos pelo teclado.\u003c/p\u003e","title":"Android 16 Edge-to-Edge com Kotlin e Compose | Kotlin Brasil"},{"content":"Sobre a vagaA Revolut busca uma pessoa Engenheira de Software Mid/Sênior com foco em Java para atuar remotamente a partir da Argentina, Brasil, Colômbia ou México.\nStack técnicaJava 17/21Kotlin e ScalaGCP e KubernetesPostgreSQL, Redis, jOOQ e FlywayGrafana, Prometheus e NewRelicSpock para testesLocalidadeVaga remota para pessoas na Argentina, Brasil, Colômbia ou México, incluindo Cidade do México e São Paulo.\n","permalink":"https://kotlin.dev.br/vagas/woxxbklu8wp0bzzy-revolut-engenheiro-a-de-software-mid-senior-java/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Revolut busca uma pessoa Engenheira de Software Mid/Sênior com foco em Java para atuar remotamente a partir da Argentina, Brasil, Colômbia ou México.\u003c/p\u003e\u003ch3\u003eStack técnica\u003c/h3\u003e\u003cul\u003e\u003cli\u003eJava 17/21\u003c/li\u003e\u003cli\u003eKotlin e Scala\u003c/li\u003e\u003cli\u003eGCP e Kubernetes\u003c/li\u003e\u003cli\u003ePostgreSQL, Redis, jOOQ e Flyway\u003c/li\u003e\u003cli\u003eGrafana, Prometheus e NewRelic\u003c/li\u003e\u003cli\u003eSpock para testes\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocalidade\u003c/h3\u003e\u003cp\u003eVaga remota para pessoas na Argentina, Brasil, Colômbia ou México, incluindo Cidade do México e São Paulo.\u003c/p\u003e","title":"Engenheiro(a) de Software Mid/Sênior (Java)"},{"content":"Performance Android deixou de ser apenas uma preocupação de times grandes. Em 2026, qualquer app Kotlin que disputa atenção na Play Store precisa abrir rápido, responder sem engasgos e manter a primeira experiência previsível mesmo em celulares intermediários. O usuário não sabe se a lentidão vem do cold start, do carregamento de classes, do primeiro frame do Compose ou de uma tela pesada demais. Ele só sente que o app parece amador.\nÉ nesse ponto que Baseline Profiles e Macrobenchmark entram no fluxo de desenvolvimento Android moderno. Baseline Profile é uma forma de dizer ao Android quais caminhos de código são importantes para compilar e otimizar antes do usuário tocar no app pela primeira vez. Macrobenchmark é a ferramenta que mede esse impacto em cenários reais: startup, scroll, navegação, troca de tela, renderização e jank. Juntas, essas duas peças transformam performance em algo testável, versionado e revisável em pull request.\nSe você já acompanha nossos guias de Android com Kotlin, Jetpack Compose, testes Android com Compose e Maestro e acessibilidade no Android, este artigo é o próximo passo: tratar performance como parte do produto, não como uma otimização tardia feita na véspera do lançamento.\nO que é Baseline Profile? Baseline Profile é um arquivo gerado a partir de fluxos importantes do app. Ele contém uma lista de classes e métodos que o Android Runtime deve priorizar na compilação ahead-of-time ou just-in-time otimizada. Na prática, o app chega ao usuário com caminhos críticos mais preparados para execução rápida.\nSem profile, o Android ainda otimiza o app com o tempo, mas a primeira sessão pode sofrer. O problema é justamente a primeira sessão: onboarding, login, tela inicial, busca, carrinho, feed ou qualquer fluxo que precisa convencer o usuário a continuar. Em apps Compose, isso também ajuda porque a primeira composição de telas complexas pode carregar bastante código do runtime, Material, navegação, imagens, ViewModels e camadas de dados.\nBaseline Profile não substitui arquitetura, cache ou UI leve. Ele não corrige uma tela que faz chamada de rede no main thread, não resolve recomposição infinita e não transforma uma consulta lenta em rápida. A vantagem é outra: reduzir o custo inicial de executar caminhos que já são importantes e bem definidos.\nQuando vale investir nisso? Baseline Profiles fazem mais sentido quando o app já tem uma base mínima de qualidade e precisa melhorar experiência real. Alguns sinais comuns:\ncold start perceptivelmente lento; primeira navegação para tela inicial demora; tela Compose principal engasga na primeira renderização; app tem muitos módulos, bibliotecas ou inicializadores; time quer medir performance antes e depois de mudanças; app já usa CI/CD e consegue rodar testes instrumentados em device ou emulator controlado. Se o projeto ainda está quebrando por falta de testes básicos, comece pelo guia de testes Kotlin e por fluxos críticos automatizados. Mas se o app já tem uma trilha confiável de build, Baseline Profile é uma melhoria de alto retorno.\nEstrutura mínima de módulos O setup moderno costuma ter pelo menos três partes:\nmódulo do app, por exemplo :app; módulo de benchmark, por exemplo :benchmark; testes que geram profile e medem cenários críticos. No Gradle Kotlin DSL, o módulo de benchmark usa plugins Android específicos. A configuração exata muda com versões do Android Gradle Plugin, então trate o exemplo como ponto de partida:\nplugins { id(\u0026#34;com.android.test\u0026#34;) id(\u0026#34;org.jetbrains.kotlin.android\u0026#34;) id(\u0026#34;androidx.baselineprofile\u0026#34;) } android { namespace = \u0026#34;br.dev.kotlin.benchmark\u0026#34; compileSdk = 36 defaultConfig { minSdk = 28 targetProjectPath = \u0026#34;:app\u0026#34; testInstrumentationRunner = \u0026#34;androidx.test.runner.AndroidJUnitRunner\u0026#34; } } dependencies { implementation(\u0026#34;androidx.test.ext:junit:1.2.1\u0026#34;) implementation(\u0026#34;androidx.test.espresso:espresso-core:3.6.1\u0026#34;) implementation(\u0026#34;androidx.benchmark:benchmark-macro-junit4:1.3.4\u0026#34;) } No módulo do app, o plugin de baseline profile conecta o artefato gerado ao build final:\nplugins { id(\u0026#34;com.android.application\u0026#34;) id(\u0026#34;org.jetbrains.kotlin.android\u0026#34;) id(\u0026#34;androidx.baselineprofile\u0026#34;) } dependencies { baselineProfile(project(\u0026#34;:benchmark\u0026#34;)) } A parte importante não é decorar versões. É entender que profile precisa ser gerado por fluxos reais e depois empacotado com o app. Sem isso, o benchmark vira apenas um teste isolado.\nGerando um Baseline Profile simples Um teste de geração de profile deve abrir o app e percorrer os caminhos mais valiosos. Para um app de conteúdo, pode ser abrir home, entrar em artigo e voltar. Para e-commerce, home, busca, produto e carrinho. Para banco, login simulado, saldo e extrato. O exemplo abaixo mostra a ideia:\n@RunWith(AndroidJUnit4::class) class BaselineProfileGenerator { @get:Rule val baselineProfileRule = BaselineProfileRule() @Test fun gerarProfilePrincipal() { baselineProfileRule.collect( packageName = \u0026#34;br.dev.kotlin.app\u0026#34;, ) { pressHome() startActivityAndWait() device.waitForIdle() device.findObject(By.text(\u0026#34;Entrar\u0026#34;)).click() device.waitForIdle() device.findObject(By.text(\u0026#34;Explorar artigos\u0026#34;)).click() device.waitForIdle() device.findObject(By.textContains(\u0026#34;Kotlin\u0026#34;)).click() device.waitForIdle() } } } Esse teste usa UI Automator porque o objetivo é simular uso real pelo sistema, não testar uma função interna. Ele deve ser estável, curto e representativo. Um profile gigante com fluxos aleatórios é difícil de revisar e pode esconder problemas. Prefira começar com o caminho que mais afeta retenção: abrir app e chegar na primeira tela útil.\nMedindo startup com Macrobenchmark Depois de gerar profile, você precisa provar que ele ajudou. Macrobenchmark mede cenários no dispositivo, com controle sobre compilação, iterações e métricas. Para startup, um teste típico fica assim:\n@RunWith(AndroidJUnit4::class) class StartupBenchmark { @get:Rule val benchmarkRule = MacrobenchmarkRule() @Test fun coldStartup() = benchmarkRule.measureRepeated( packageName = \u0026#34;br.dev.kotlin.app\u0026#34;, metrics = listOf(StartupTimingMetric()), iterations = 10, startupMode = StartupMode.COLD, compilationMode = CompilationMode.Partial( baselineProfileMode = BaselineProfileMode.Require, ), setupBlock = { pressHome() }, ) { startActivityAndWait() } } O teste mede tempo de startup em várias iterações. BaselineProfileMode.Require força o teste a falhar se o profile esperado não estiver presente, evitando uma conclusão falsa. Em CI, isso protege contra regressões em configuração.\nTambém vale medir sem profile em uma rodada local para entender o ganho. Mas não misture os resultados de qualquer jeito: emulator, device físico, versão do Android, carga da máquina e modo de compilação mudam bastante os números. O valor do benchmark está mais em comparar mudanças controladas do que em perseguir um número absoluto bonito.\nMedindo jank em telas Compose Startup é só uma parte. Apps Android modernos sofrem muito com scroll travado, listas pesadas e recomposição desnecessária. Macrobenchmark pode medir frames enquanto o teste interage com a tela:\n@RunWith(AndroidJUnit4::class) class FeedBenchmark { @get:Rule val benchmarkRule = MacrobenchmarkRule() @Test fun scrollFeedPrincipal() = benchmarkRule.measureRepeated( packageName = \u0026#34;br.dev.kotlin.app\u0026#34;, metrics = listOf(FrameTimingMetric()), iterations = 5, startupMode = StartupMode.WARM, compilationMode = CompilationMode.Partial( baselineProfileMode = BaselineProfileMode.UseIfAvailable, ), ) { startActivityAndWait() device.waitForIdle() val lista = device.findObject(By.res(\u0026#34;feed_list\u0026#34;)) repeat(5) { lista.fling(Direction.DOWN) device.waitForIdle() } } } Para isso funcionar bem, suas telas precisam ter identificadores estáveis. Em Compose, exponha testTag quando fizer sentido:\nLazyColumn( modifier = Modifier.testTag(\u0026#34;feed_list\u0026#34;), ) { items(artigos, key = { it.id }) { artigo -\u0026gt; ArtigoCard(artigo = artigo) } } A mesma disciplina que ajuda testes de UI ajuda benchmarks. Elementos identificáveis tornam automação mais confiável. Chaves estáveis em listas reduzem recomposição errada. Estados bem separados facilitam investigar gargalo.\nChecklist de performance antes do profile Baseline Profile potencializa um app saudável. Antes de culpar o runtime, revise pontos simples:\ninicialização preguiçosa para SDKs que não precisam rodar no Application.onCreate; chamadas de rede e banco fora do main thread; imagens redimensionadas e carregadas com cache; LazyColumn com key estável em listas dinâmicas; remember e derivedStateOf usados apenas onde realmente ajudam; ViewModels sem trabalho pesado no construtor; navegação sem recriar grafo inteiro a cada recomposição; logs verbosos desativados em release; dependências antigas removidas do startup path. Depois disso, Baseline Profile reduz custo de execução dos caminhos críticos. Antes disso, ele pode mascarar sintomas sem corrigir a causa.\nComo encaixar no CI/CD Rodar Macrobenchmark em todo commit pode ser caro. Uma estratégia prática é separar três níveis:\ntestes unitários e de ViewModel em todo pull request; testes instrumentados essenciais em branches principais; Macrobenchmark e geração de Baseline Profile em agenda diária, release candidate ou mudanças que mexem em startup, navegação e UI. Em projetos com GitHub Actions, Bitrise, GitLab CI ou runners próprios, use um device/emulator consistente e salve artefatos de benchmark. O objetivo é enxergar tendência. Se o cold start subiu 20% depois de adicionar um SDK de analytics, o time precisa saber antes do deploy.\nTambém vale criar uma regra social: mudança que adiciona inicializador, dependência global, tela inicial nova ou lista pesada precisa olhar benchmark. Performance vira critério de revisão, igual cobertura de teste e acessibilidade.\nErros comuns O primeiro erro é gerar profile navegando por fluxos que ninguém usa. Profile deve refletir negócio: login, home, compra, busca, leitura, upload, checkout, reprodução, ou outro caminho que sustenta retenção.\nO segundo erro é rodar benchmark em ambiente instável e discutir milissegundos como se fossem verdade absoluta. Compare cenários iguais, use várias iterações e olhe tendência.\nO terceiro erro é achar que Baseline Profile resolve toda performance. Se o app trava porque a tela faz processamento pesado durante recomposição, o profile só torna parte do código mais rápida. A arquitetura ainda precisa melhorar.\nO quarto erro é esquecer a experiência acessível. Um app pode abrir rápido e ainda ser ruim para quem usa TalkBack, fonte grande ou navegação por teclado. Performance, testes e acessibilidade precisam andar juntos, especialmente em times Android profissionais.\nUm fluxo recomendado para times Kotlin Para um time que quer começar sem exagero, eu seguiria este caminho:\nescolha um device ou emulator padrão para medições; crie módulo :benchmark; gere Baseline Profile para cold start e primeira navegação útil; adicione um benchmark de startup; adicione um benchmark de scroll da tela mais importante; rode localmente antes de releases; automatize em CI quando o fluxo estiver estável; registre resultados em cada mudança relevante. Esse fluxo combina bem com uma base Kotlin moderna: Gradle Kotlin DSL, módulos separados, Compose, coroutines, testes com Turbine e boas práticas de arquitetura. Para quem trabalha com produto Android no Brasil, esse tipo de maturidade técnica diferencia uma candidatura de desenvolvedor pleno/sênior e ajuda empresas a reduzir reclamações invisíveis de usuários.\nConclusão Baseline Profiles e Macrobenchmark colocam performance Android em um lugar mais saudável: medição antes de opinião. Com Kotlin e Compose, é fácil criar telas ricas, mas também é fácil acumular custo de startup, recomposição e navegação sem perceber. Um profile bem escolhido acelera os caminhos críticos. Um benchmark bem escrito mostra se a mudança realmente ajudou.\nComece pequeno: cold start, home e a tela que mais importa para o negócio. Depois expanda para scroll, navegação e fluxos de conversão. O objetivo não é ganhar uma competição de milissegundos; é entregar um app que parece rápido desde a primeira sessão, em aparelhos reais, para usuários reais.\nPara complementar o estudo, revise também WorkManager com Kotlin no Android, Paging 3 com Kotlin e Compose e segurança de dados locais no Android. Performance fica mais fácil quando arquitetura, dados, testes e experiência de usuário foram pensados como um sistema só. Se você trabalha com apps de produção, vale acompanhar também o ecossistema Android em sites irmãos como Python Brasil, especialmente para comparar práticas de CI, métricas e automação entre stacks.\n","permalink":"https://kotlin.dev.br/blog/baseline-profiles-macrobenchmark-android-kotlin-2026/","summary":"\u003cp\u003ePerformance Android deixou de ser apenas uma preocupação de times grandes. Em 2026, qualquer app Kotlin que disputa atenção na Play Store precisa abrir rápido, responder sem engasgos e manter a primeira experiência previsível mesmo em celulares intermediários. O usuário não sabe se a lentidão vem do cold start, do carregamento de classes, do primeiro frame do Compose ou de uma tela pesada demais. Ele só sente que o app parece amador.\u003c/p\u003e","title":"Baseline Profiles no Android com Kotlin em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA Applaudo busca uma pessoa Desenvolvedora Android de nível pleno para atuação remota a partir de Bogotá, Colômbia.\nRequisitosExperiência com desenvolvimento Android.Conhecimento em Kotlin e Android SDK.Experiência com Android WebView.Conhecimentos em JavaScript e CSS.Uso de Git no fluxo de desenvolvimento. ","permalink":"https://kotlin.dev.br/vagas/n3ix9myt7259okle-applaudo-desenvolvedor-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Applaudo busca uma pessoa Desenvolvedora Android de nível pleno para atuação remota a partir de Bogotá, Colômbia.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eAndroid SDK\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eAndroid WebView\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimentos em \u003cstrong\u003eJavaScript\u003c/strong\u003e e \u003cstrong\u003eCSS\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eGit\u003c/strong\u003e no fluxo de desenvolvimento.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android"},{"content":"Sobre a vagaA Platform Science busca um(a) Engenheiro(a) de Software Líder em nível sênior para atuar em modelo híbrido, com base em Londrina ou no Brasil.\nStack principalLinguagens e frameworks: Kotlin, Java, Spring Boot, React e Angular.Bancos de dados: PostgreSQL, MySQL, MongoDB, Redis e Elasticsearch.Cloud e infraestrutura: AWS, Azure, GCP, Docker, Kubernetes e Terraform.Mensageria e entrega: Kafka, RabbitMQ e CI/CD.RequisitosExperiência sênior em engenharia de software.Vivência com desenvolvimento backend usando Kotlin, Java e Spring Boot.Conhecimento em bancos relacionais e NoSQL.Experiência com cloud, containers, orquestração e pipelines de CI/CD.Capacidade de liderar tecnicamente decisões de arquitetura e desenvolvimento. ","permalink":"https://kotlin.dev.br/vagas/0en1lpz52lz4p71a-platform-science-engenheiro-a-de-software-lider/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Platform Science busca um(a) Engenheiro(a) de Software Líder em nível sênior para atuar em modelo híbrido, com base em Londrina ou no Brasil.\u003c/p\u003e\u003ch3\u003eStack principal\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eLinguagens e frameworks:\u003c/strong\u003e Kotlin, Java, Spring Boot, React e Angular.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eBancos de dados:\u003c/strong\u003e PostgreSQL, MySQL, MongoDB, Redis e Elasticsearch.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eCloud e infraestrutura:\u003c/strong\u003e AWS, Azure, GCP, Docker, Kubernetes e Terraform.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eMensageria e entrega:\u003c/strong\u003e Kafka, RabbitMQ e CI/CD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software.\u003c/li\u003e\u003cli\u003eVivência com desenvolvimento backend usando Kotlin, Java e Spring Boot.\u003c/li\u003e\u003cli\u003eConhecimento em bancos relacionais e NoSQL.\u003c/li\u003e\u003cli\u003eExperiência com cloud, containers, orquestração e pipelines de CI/CD.\u003c/li\u003e\u003cli\u003eCapacidade de liderar tecnicamente decisões de arquitetura e desenvolvimento.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Líder"},{"content":"Sobre a vagaA Platform Science busca uma pessoa Software Engineer Pleno para atuar em modelo híbrido, com base em Londrina ou Brasil.\nTecnologiasKotlin, Java, Node.js e AndroidReact e AngularPostgreSQL, MySQL, MongoDB, Redis e ElasticsearchAWS, Azure, GCP, Terraform, Lambda, SQS e Step FunctionsKafka e RabbitMQRequisitosExperiência em desenvolvimento de software em nível pleno.Vivência com backend, aplicações web ou mobile.Conhecimento prático em bancos de dados, mensageria e serviços em cloud. ","permalink":"https://kotlin.dev.br/vagas/ry1v5hur5a2gwhw5-platform-science-engenheiro-a-de-software-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Platform Science busca uma pessoa Software Engineer Pleno para atuar em modelo híbrido, com base em Londrina ou Brasil.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java, Node.js e Android\u003c/li\u003e\u003cli\u003eReact e Angular\u003c/li\u003e\u003cli\u003ePostgreSQL, MySQL, MongoDB, Redis e Elasticsearch\u003c/li\u003e\u003cli\u003eAWS, Azure, GCP, Terraform, Lambda, SQS e Step Functions\u003c/li\u003e\u003cli\u003eKafka e RabbitMQ\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento de software em nível pleno.\u003c/li\u003e\u003cli\u003eVivência com backend, aplicações web ou mobile.\u003c/li\u003e\u003cli\u003eConhecimento prático em bancos de dados, mensageria e serviços em cloud.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Pleno"},{"content":"Sobre a vagaA CookUnity busca uma pessoa Engenheira Full Stack Sênior para atuar em MarTech em modelo remoto, com elegibilidade para América do Sul ou Argentina.\nResponsabilidadesDesenvolver e manter soluções full stack para produtos e integrações de marketing.Trabalhar com serviços backend, APIs HTTP, WebSockets, Server-Sent Events e webhooks.Integrar plataformas e ferramentas como Segment, StatSig, Google Ads, Meta, TikTok e Snowflake.Colaborar com equipes de produto, dados e marketing para entregar soluções escaláveis.RequisitosExperiência sênior em desenvolvimento full stack.Conhecimento em Kotlin, Java, Node.js, TypeScript e React.Experiência com integrações de APIs, eventos e sistemas distribuídos.Familiaridade com dados e ferramentas de marketing digital.DiferenciaisExperiência com ferramentas de IA como ChatGPT ou Claude.Vivência em ambientes MarTech ou growth engineering. ","permalink":"https://kotlin.dev.br/vagas/e4pj93z51cir406p-cookunity-engenheiro-a-full-stack-senior-martech/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CookUnity busca uma pessoa Engenheira Full Stack Sênior para atuar em MarTech em modelo remoto, com elegibilidade para América do Sul ou Argentina.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter soluções full stack para produtos e integrações de marketing.\u003c/li\u003e\u003cli\u003eTrabalhar com serviços backend, APIs HTTP, WebSockets, Server-Sent Events e webhooks.\u003c/li\u003e\u003cli\u003eIntegrar plataformas e ferramentas como Segment, StatSig, Google Ads, Meta, TikTok e Snowflake.\u003c/li\u003e\u003cli\u003eColaborar com equipes de produto, dados e marketing para entregar soluções escaláveis.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento full stack.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Java, Node.js, TypeScript e React.\u003c/li\u003e\u003cli\u003eExperiência com integrações de APIs, eventos e sistemas distribuídos.\u003c/li\u003e\u003cli\u003eFamiliaridade com dados e ferramentas de marketing digital.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com ferramentas de IA como ChatGPT ou Claude.\u003c/li\u003e\u003cli\u003eVivência em ambientes MarTech ou growth engineering.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) Full Stack Sênior, MarTech"},{"content":"Desenvolvedor Kotlin Multiplatform em 2026: por que essa carreira importa O papel de desenvolvedor Kotlin Multiplatform deixou de ser uma curiosidade para virar uma especialização real dentro de times mobile e produto. A promessa é simples: compartilhar código Kotlin entre Android, iOS, backend, desktop ou web sem abrir mão da experiência nativa quando ela é importante. Para empresas brasileiras que mantêm dois apps, múltiplos squads e muita regra de negócio duplicada, essa proposta reduz retrabalho e melhora consistência.\nNa prática, a pessoa desenvolvedora KMP atua no ponto de encontro entre Android com Kotlin, iOS, arquitetura mobile, APIs e qualidade de software. Ela não é apenas uma pessoa Android que escreve um módulo compartilhado. O diferencial está em saber decidir o que compartilhar, o que deixar nativo, como testar a lógica comum e como organizar a evolução do produto sem travar os times de plataforma.\nEsse guia mostra como entrar nessa carreira em 2026, quais habilidades priorizar, que projetos colocar no portfólio, quais faixas salariais observar e como usar o conteúdo técnico do Kotlin Brasil para montar uma trilha de estudos objetiva.\nO que faz um desenvolvedor Kotlin Multiplatform Um desenvolvedor Kotlin Multiplatform constrói e mantém módulos compartilhados em Kotlin para mais de uma plataforma. O uso mais comum é compartilhar lógica entre Android e iOS, mas KMP também pode atender desktop, web, bibliotecas internas e até backends que reaproveitam modelos, validações e clientes HTTP.\nAs responsabilidades mais comuns incluem:\ndesenhar a fronteira entre código compartilhado e código nativo; criar módulos commonMain, androidMain e iosMain bem organizados; implementar networking com Ktor Client, serialização e tratamento de erros; modelar estados, casos de uso, repositórios e validações reutilizáveis; escrever testes unitários no código comum; expor APIs amigáveis para Android, Swift e SwiftUI; investigar problemas de build, Gradle, Kotlin/Native e integração com Xcode; apoiar decisões entre KMP, Flutter, React Native e desenvolvimento nativo. Em empresas com apps maduros, KMP costuma entrar primeiro em áreas onde duplicação dói mais: autenticação, regras financeiras, catálogo, checkout, sincronização offline, feature flags, analytics, validação de formulários e clientes de API. A interface pode continuar nativa em SwiftUI e Jetpack Compose, enquanto a lógica crítica fica compartilhada.\nHabilidades técnicas mais valorizadas Kotlin avançado KMP exige domínio de Kotlin além da sintaxe básica. É importante conhecer null safety, data classes, sealed classes, generics, extension functions, lambdas, coleções, imutabilidade, coroutines e Flow. A base de programação assíncrona é essencial porque muito código compartilhado lida com rede, cache, eventos e estados de tela.\nSe você ainda está consolidando a linguagem, comece pelo tutorial de Kotlin Multiplatform depois de revisar fundamentos como coroutines, Flow e serialization.\nArquitetura mobile Uma pessoa KMP precisa entender como apps reais são estruturados. MVVM, Clean Architecture, repositórios, casos de uso, injeção de dependência, estado de UI, offline-first e camadas de dados aparecem com frequência. Mesmo quando o código compartilhado não renderiza tela, ele precisa conversar bem com ViewModels Android, SwiftUI, Combine, async/await e ciclos de vida diferentes.\nGradle e build multiplataforma Boa parte da curva de aprendizado está no build. O arquivo build.gradle.kts define targets, source sets, dependências e publicação dos artefatos. Saber diagnosticar conflito de versão, dependência que não suporta iOS, configuração de framework e cache de build economiza muitas horas em projetos reais.\niOS suficiente para colaborar Não é obrigatório virar especialista em Swift, mas é difícil ser produtivo em KMP sem entender o básico do ecossistema iOS. Você precisa saber abrir o projeto no Xcode, ler erros de compilação, entender frameworks, interoperabilidade Swift-Kotlin, tipos opcionais, concorrência e como a API compartilhada aparece para o time iOS.\nTestes e qualidade Um dos maiores ganhos de KMP é testar regras de negócio uma vez só. Por isso, testes unitários no commonTest, mocks simples, validação de serialização, testes de repositório e contratos de API são diferenciais fortes. Em times maduros, o módulo compartilhado precisa ser confiável o suficiente para ser usado por duas plataformas sem medo.\nRoadmap para se tornar desenvolvedor KMP Fase 1: base Kotlin e Android ou backend Comece dominando Kotlin em um ambiente estável. Para a maioria das pessoas, Android é o caminho mais natural porque KMP nasceu muito próximo do ecossistema mobile. Construa apps com Jetpack Compose, ViewModel, coroutines, Room, Retrofit ou Ktor Client. Se seu ponto de partida é backend, foque em Ktor, Spring Boot, serialização, testes e arquitetura de domínio.\nFase 2: primeiro módulo compartilhado Crie um projeto simples com commonMain, androidMain e iosMain. Compartilhe modelos, validações e um cliente HTTP pequeno. O objetivo não é criar o app perfeito, mas entender expect/actual, source sets, dependências multiplataforma e como o Android e o iOS consomem o mesmo código.\nFase 3: estado, cache e testes Depois do primeiro módulo, evolua para algo mais realista: login, catálogo, favoritos, carrinho, busca, carteira ou lista offline. Inclua testes em commonTest, erros tipados, cache local com biblioteca compatível e estados observáveis com Flow. Essa fase mostra que você sabe lidar com problemas de produto, não só com configuração.\nFase 4: integração com app existente O mercado valoriza quem sabe introduzir KMP sem reescrever tudo. Pegue um app Android já pronto e extraia uma regra de negócio para um módulo compartilhado. Documente o que foi compartilhado, o que ficou nativo e quais trade-offs apareceram. Esse projeto conta muito em entrevistas porque simula a adoção gradual que empresas realmente fazem.\nFase 5: especialização Escolha uma trilha de profundidade: mobile architecture, Compose Multiplatform, bibliotecas KMP, performance, offline-first, segurança, integração iOS ou developer experience. Profissionais que combinam KMP com uma especialidade clara tendem a se destacar mais do que generalistas que sabem apenas criar o template inicial.\nProjetos de portfólio que chamam atenção Um portfólio KMP forte precisa provar que você entende produto e integração. Boas ideias incluem:\napp de finanças com regras de cálculo compartilhadas entre Android e iOS; catálogo offline-first com busca, favoritos e sincronização; cliente de API com Ktor, kotlinx.serialization e tratamento de erros tipado; biblioteca de validação de formulários usada por dois apps; app de hábitos com camada de domínio compartilhada e UI nativa; módulo de feature flags compartilhado com testes de contrato. Evite projetos que apenas mostram a tela padrão do wizard. Em vez disso, escreva um README explicando a arquitetura, os source sets, as dependências, as decisões de compartilhamento e como rodar os testes. Se possível, publique capturas de tela do Android e do iOS consumindo a mesma lógica.\nSalário e mercado para KMP no Brasil Kotlin Multiplatform ainda é uma especialização menor que Android nativo e backend Kotlin, mas tende a pagar bem pela escassez. No panorama de Kotlin no mercado de trabalho, a trilha multiplataforma aparece como uma das áreas de crescimento acelerado, especialmente em empresas com produto mobile forte.\nComo referência prática para 2026, profissionais KMP costumam se posicionar acima da faixa Android equivalente quando conseguem provar experiência real:\nNível CLT mensal PJ mensal Perfil típico Júnior/entrada R$ 4.000 - R$ 7.000 R$ 5.000 - R$ 9.000 Android ou Kotlin sólido, primeiro projeto KMP no portfólio Pleno R$ 8.000 - R$ 15.000 R$ 11.000 - R$ 22.000 Módulos compartilhados, testes, integração com app real Sênior R$ 15.000 - R$ 26.000 R$ 22.000 - R$ 40.000+ Arquitetura, adoção gradual, iOS, DX e liderança técnica Essas faixas variam por região, inglês, senioridade, setor e modelo de contratação. Fintechs, bancos digitais, healthtechs, e-commerces e empresas com apps de alto volume tendem a valorizar mais a especialização porque duplicação de regra de negócio custa caro.\nComo encontrar vagas de Kotlin Multiplatform Nem toda vaga usa o título “desenvolvedor Kotlin Multiplatform”. Procure também por “Android KMP”, “mobile engineer Kotlin”, “Compose Multiplatform”, “shared mobile architecture”, “Kotlin iOS”, “engenheiro mobile sênior” e “Kotlin Multiplatform Mobile”. Algumas empresas listam KMP como diferencial em vagas Android ou mobile fullstack.\nNo Kotlin Brasil, acompanhe a seção de vagas Kotlin e filtre mentalmente por anúncios que citam KMP, Compose Multiplatform, iOS, Swift, arquitetura mobile ou compartilhamento de código. Também vale revisar vagas Kotlin remoto quando você já tiver inglês e experiência suficiente para competir em oportunidades internacionais.\nKMP, Flutter ou React Native para carreira? Para carreira, a melhor escolha depende do seu ponto de partida. Se você já vem de Android, Kotlin ou backend JVM, KMP aproveita muito do seu repertório e cria um diferencial natural. Se você quer criar interfaces multiplataforma rapidamente sem depender de conhecimento nativo, Flutter pode ser mais direto. Se sua base é JavaScript e produto web, React Native pode ser uma ponte mais confortável.\nO ponto forte de KMP é entrar bem em empresas que já têm apps nativos e não querem jogar anos de investimento fora. Por isso, ele costuma aparecer em ambientes onde qualidade, performance, consistência de regra de negócio e evolução gradual são mais importantes do que velocidade inicial de prototipação. Para uma comparação técnica mais detalhada, veja Kotlin Multiplatform vs Flutter.\nPlano de estudos de 90 dias Nos primeiros 30 dias, revise Kotlin, coroutines, Flow, serialização e arquitetura básica. Faça pequenos exercícios com modelos, validações e chamadas HTTP.\nEntre os dias 31 e 60, crie um projeto KMP simples com Android e iOS. Configure source sets, Ktor Client, kotlinx.serialization, testes e uma camada de domínio compartilhada. Documente tudo.\nEntre os dias 61 e 90, transforme o projeto em algo apresentável: adicione cache, estados de erro, testes, README, decisões de arquitetura e uma pequena comparação entre UI nativa e lógica compartilhada. Termine com um post técnico ou estudo de caso no GitHub explicando o que você aprendeu.\nConclusão Ser desenvolvedor Kotlin Multiplatform em 2026 é uma oportunidade forte para quem quer crescer além do Android tradicional sem abandonar Kotlin. O mercado ainda é menor que o de Android nativo, mas a combinação de escassez, impacto em produto e adoção gradual cria espaço para profissionais bem preparados.\nO caminho mais seguro é construir uma base Kotlin sólida, dominar arquitetura mobile, entender iOS o suficiente para colaborar e criar projetos que provem uso real de código compartilhado. Comece pelo tutorial de Kotlin Multiplatform, aprofunde o roadmap Android e conecte seu portfólio às demandas reais das vagas Kotlin no Brasil.\n","permalink":"https://kotlin.dev.br/carreira/desenvolvedor-kotlin-multiplatform/","summary":"\u003ch2 id=\"desenvolvedor-kotlin-multiplatform-em-2026-por-que-essa-carreira-importa\"\u003eDesenvolvedor Kotlin Multiplatform em 2026: por que essa carreira importa\u003c/h2\u003e\n\u003cp\u003eO papel de \u003cstrong\u003edesenvolvedor Kotlin Multiplatform\u003c/strong\u003e deixou de ser uma curiosidade para virar uma especialização real dentro de times mobile e produto. A promessa é simples: compartilhar código Kotlin entre Android, iOS, backend, desktop ou web sem abrir mão da experiência nativa quando ela é importante. Para empresas brasileiras que mantêm dois apps, múltiplos squads e muita regra de negócio duplicada, essa proposta reduz retrabalho e melhora consistência.\u003c/p\u003e","title":"Desenvolvedor Kotlin Multiplatform: Carreira, Salário e Roadmap 2026"},{"content":"Flow virou uma das peças centrais do Kotlin moderno. Ele aparece em ViewModels Android, repositórios com Room, integrações com APIs, pipelines backend, streamings em Ktor e até em fluxos de IA que precisam emitir estado parcial. O problema é que muita equipe aprende a escrever Flow, mas continua testando código assíncrono com delay, Thread.sleep, mocks frágeis ou asserts feitos cedo demais. O resultado são testes lentos, instáveis e pouco confiáveis.\nÉ aí que entra o Turbine, uma biblioteca simples e muito prática para testar emissões de Flow, StateFlow e SharedFlow. Em vez de coletar manualmente uma lista, controlar coroutine na mão e torcer para o tempo bater, você escreve o teste como uma conversa com o fluxo: espera o próximo item, valida o valor, confirma que não há eventos extras ou cancela a coleta de forma explícita.\nEste guia mostra como usar Turbine com kotlinx-coroutines-test, runTest, ViewModel e eventos de UI. Se você ainda está revisando a base, leia também nosso conteúdo sobre Kotlin Flow, coroutines em Kotlin e o guia de testes Kotlin. A ideia aqui é sair do conceito e chegar em testes que um time consegue manter em produção.\nPor que testar Flow exige cuidado? Um Flow não é apenas uma função que retorna um valor. Ele pode emitir vários valores, suspender, trocar de dispatcher, combinar fontes, lidar com erro, manter estado quente ou depender do ciclo de vida de quem coleta. Isso muda a forma de testar.\nAlguns problemas comuns aparecem rápido:\no teste termina antes do Flow emitir; um delay real deixa a suíte lenta; um StateFlow emite o estado inicial e o teste ignora isso; um SharedFlow perde evento porque ninguém estava coletando; uma coroutine fica ativa depois do teste; a ordem das emissões muda por causa de concorrência mal controlada. Turbine ajuda porque coloca essas expectativas no código do teste. Você deixa claro quando espera um item, quando não espera mais nada e quando a coleta deve acabar. Isso reduz testes intermitentes, principalmente em projetos Android com ViewModel, StateFlow e eventos de tela.\nDependências recomendadas Em um projeto Kotlin com Gradle, normalmente você combina Turbine com kotlinx-coroutines-test. As versões mudam, então confira a versão atual antes de publicar em um projeto real.\ndependencies { testImplementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2\u0026#34;) testImplementation(\u0026#34;app.cash.turbine:turbine:1.2.0\u0026#34;) } Para testes Android locais de ViewModel, você também costuma usar JUnit, MockK ou fakes manuais. O importante é que a regra de negócio testada rode na JVM sempre que possível. Testes instrumentados devem ficar para o que depende de framework Android, renderização ou integração real de dispositivo. Essa separação conversa bem com o nosso guia de testes Android com Compose e Maestro.\nPrimeiro teste com Flow simples Vamos começar com um caso pequeno. Imagine um repositório que emite o progresso de sincronização de dados.\nclass SincronizacaoRepository { fun progresso(): Flow\u0026lt;Int\u0026gt; = flow { emit(0) emit(50) emit(100) } } Com Turbine, o teste fica direto:\nimport app.cash.turbine.test import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertEquals class SincronizacaoRepositoryTest { @Test fun `deve emitir progresso em ordem`() = runTest { val repository = SincronizacaoRepository() repository.progresso().test { assertEquals(0, awaitItem()) assertEquals(50, awaitItem()) assertEquals(100, awaitItem()) awaitComplete() } } } O ganho é legibilidade. O teste diz exatamente o que o fluxo deve emitir e em qual ordem. awaitComplete() confirma que o Flow terminou. Se uma emissão faltar, sobrar ou vier fora de ordem, o teste falha de forma compreensível.\nTestando StateFlow em ViewModel StateFlow é um pouco diferente porque sempre possui um valor atual. Quando você começa a coletar, o primeiro item normalmente é o estado inicial. Isso é correto, mas costuma pegar iniciantes de surpresa.\ndata class BuscaUiState( val carregando: Boolean = false, val resultados: List\u0026lt;String\u0026gt; = emptyList(), val erro: String? = null, ) class BuscaViewModel( private val service: BuscaService, ) : ViewModel() { private val _uiState = MutableStateFlow(BuscaUiState()) val uiState: StateFlow\u0026lt;BuscaUiState\u0026gt; = _uiState.asStateFlow() fun buscar(termo: String) { viewModelScope.launch { _uiState.value = BuscaUiState(carregando = true) val resultados = service.buscar(termo) _uiState.value = BuscaUiState(resultados = resultados) } } } Um teste saudável valida o estado inicial, a transição de carregamento e o estado final:\n@Test fun `deve atualizar estado ao buscar resultados`() = runTest { val service = FakeBuscaService(resultados = listOf(\u0026#34;Kotlin\u0026#34;, \u0026#34;Compose\u0026#34;)) val viewModel = BuscaViewModel(service) viewModel.uiState.test { assertEquals(BuscaUiState(), awaitItem()) viewModel.buscar(\u0026#34;kot\u0026#34;) assertEquals(BuscaUiState(carregando = true), awaitItem()) assertEquals( BuscaUiState(resultados = listOf(\u0026#34;Kotlin\u0026#34;, \u0026#34;Compose\u0026#34;)), awaitItem(), ) cancelAndIgnoreRemainingEvents() } } cancelAndIgnoreRemainingEvents() é útil quando o fluxo é quente e não termina sozinho, como um StateFlow exposto por ViewModel. Sem isso, o teste pode ficar esperando conclusão que nunca virá. O ponto é assumir explicitamente que aquele fluxo continua vivo, mas que as emissões relevantes já foram validadas.\nTestando erro sem depender de exceção solta Em UI Android, muitas equipes preferem representar erro dentro do estado em vez de deixar exceção escapar para a camada visual. Isso torna o comportamento mais previsível.\n@Test fun `deve mostrar erro quando busca falhar`() = runTest { val service = FakeBuscaService(erro = IllegalStateException(\u0026#34;API fora do ar\u0026#34;)) val viewModel = BuscaViewModel(service) viewModel.uiState.test { awaitItem() // estado inicial viewModel.buscar(\u0026#34;kotlin\u0026#34;) assertEquals(true, awaitItem().carregando) val estadoErro = awaitItem() assertEquals(false, estadoErro.carregando) assertEquals(\u0026#34;API fora do ar\u0026#34;, estadoErro.erro) cancelAndIgnoreRemainingEvents() } } Essa abordagem força o ViewModel a transformar falhas em estado visível. Para produto, isso é melhor do que ter uma tela silenciosa ou uma coroutine cancelada sem feedback. Para o teste, também evita depender de stack trace como contrato de comportamento.\nSharedFlow para eventos pontuais SharedFlow costuma aparecer em eventos que não são exatamente estado: navegação, snackbar, analytics, pedido de foco ou confirmação de ação. O cuidado é que eventos podem ser perdidos se a coleta começar tarde demais.\nsealed interface PerfilEvento { data object NavegarParaHome : PerfilEvento data class MostrarMensagem(val texto: String) : PerfilEvento } class PerfilViewModel : ViewModel() { private val _eventos = MutableSharedFlow\u0026lt;PerfilEvento\u0026gt;() val eventos: SharedFlow\u0026lt;PerfilEvento\u0026gt; = _eventos.asSharedFlow() fun salvar() { viewModelScope.launch { _eventos.emit(PerfilEvento.MostrarMensagem(\u0026#34;Perfil salvo\u0026#34;)) _eventos.emit(PerfilEvento.NavegarParaHome) } } } No teste, comece a coletar antes de disparar a ação:\n@Test fun `deve emitir eventos ao salvar perfil`() = runTest { val viewModel = PerfilViewModel() viewModel.eventos.test { viewModel.salvar() assertEquals( PerfilEvento.MostrarMensagem(\u0026#34;Perfil salvo\u0026#34;), awaitItem(), ) assertEquals(PerfilEvento.NavegarParaHome, awaitItem()) expectNoEvents() cancelAndIgnoreRemainingEvents() } } expectNoEvents() documenta que a ação não deve emitir mais nada naquele momento. Esse detalhe parece pequeno, mas captura regressões comuns, como duas snackbars duplicadas ou navegação disparada duas vezes depois de uma refatoração.\nEvite delay real no teste O erro mais comum em testes de coroutines é colocar delay(1000) para esperar emissão. Isso deixa a suíte lenta e ainda não garante determinismo. Com runTest, você pode controlar tempo virtual quando o código usa delays bem estruturados.\nfun ticker(): Flow\u0026lt;Int\u0026gt; = flow { emit(1) delay(1_000) emit(2) } @Test fun `deve emitir depois do tempo virtual`() = runTest { ticker().test { assertEquals(1, awaitItem()) testScheduler.advanceTimeBy(1_000) assertEquals(2, awaitItem()) awaitComplete() } } Tempo virtual torna o teste rápido e previsível. Se o seu código depende de Dispatchers.IO, Dispatchers.Main ou escopos externos, injete dispatchers no componente testado. Essa prática melhora testabilidade e também deixa a arquitetura mais clara.\nBoas práticas para Turbine em projetos reais Algumas regras ajudam a manter a suíte saudável:\nvalide o estado inicial de StateFlow em vez de ignorá-lo sem pensar; use fakes simples para regra de negócio antes de recorrer a mocks complexos; evite Thread.sleep e delay real em testes; cancele fluxos quentes com cancelAndIgnoreRemainingEvents(); use expectNoEvents() quando ausência de emissão é parte do contrato; prefira testar ViewModel e use cases na JVM; mantenha testes instrumentados para UI, permissões, navegação real e integração de framework. Também vale separar teste de transformação e teste de UI. Se uma função transforma Flow\u0026lt;Pedido\u0026gt; em Flow\u0026lt;ResumoPedido\u0026gt;, teste essa transformação isoladamente. Se o ViewModel apenas conecta a transformação ao estado da tela, teste a transição de UiState. Não tente cobrir tudo em um único teste gigante.\nTurbine no backend Kotlin Embora Turbine apareça muito em Android, ele também é útil no backend. Em Ktor, Spring WebFlux ou pipelines internos, Flow pode representar streaming de eventos, processamento de mensagens, tarefas em lote ou respostas parciais. Testar emissões com Turbine ajuda a validar ordem, erro e conclusão sem subir infraestrutura completa.\nclass RelatorioService { fun gerarEventos(): Flow\u0026lt;String\u0026gt; = flow { emit(\u0026#34;iniciado\u0026#34;) emit(\u0026#34;processando\u0026#34;) emit(\u0026#34;concluido\u0026#34;) } } @Test fun `deve emitir eventos do relatorio`() = runTest { val service = RelatorioService() service.gerarEventos().test { assertEquals(\u0026#34;iniciado\u0026#34;, awaitItem()) assertEquals(\u0026#34;processando\u0026#34;, awaitItem()) assertEquals(\u0026#34;concluido\u0026#34;, awaitItem()) awaitComplete() } } Em times poliglotas, essa disciplina se compara bem a padrões de outras linguagens. O ecossistema Python Brasil costuma usar pytest para fixtures e testes assíncronos, enquanto Go prioriza testes explícitos com tabelas e concorrência controlada. Em Kotlin, Turbine ocupa um espaço parecido para streams: deixar o comportamento assíncrono verificável sem esconder o contrato.\nChecklist final Antes de considerar seus testes de Flow maduros, revise:\no teste usa runTest; emissões são validadas em ordem; StateFlow tem estado inicial coberto; fluxos quentes são cancelados explicitamente; não existe Thread.sleep; dispatchers são injetáveis quando necessário; erros são representados de forma testável; eventos pontuais não são perdidos por coleta tardia. Turbine não substitui uma boa arquitetura, mas expõe rapidamente onde ela está frágil. Se um Flow é difícil de testar, talvez o problema esteja no excesso de responsabilidade do ViewModel, no dispatcher fixo, no evento modelado como estado ou no estado modelado como evento. Use esses testes como feedback de design, não apenas como uma etapa burocrática do CI.\nPara continuar evoluindo, combine este guia com MVVM em Kotlin, Kotlin Flow, testes com JUnit 5 e MockK e testes Android com Compose e Maestro. A diferença entre um app Kotlin que “funciona na máquina” e um app confiável em produção quase sempre passa por testes assíncronos bem escritos.\n","permalink":"https://kotlin.dev.br/blog/testando-flow-stateflow-turbine-kotlin-2026/","summary":"\u003cp\u003e\u003ccode\u003eFlow\u003c/code\u003e virou uma das peças centrais do Kotlin moderno. Ele aparece em ViewModels Android, repositórios com Room, integrações com APIs, pipelines backend, streamings em Ktor e até em fluxos de IA que precisam emitir estado parcial. O problema é que muita equipe aprende a escrever \u003ccode\u003eFlow\u003c/code\u003e, mas continua testando código assíncrono com \u003ccode\u003edelay\u003c/code\u003e, \u003ccode\u003eThread.sleep\u003c/code\u003e, mocks frágeis ou asserts feitos cedo demais. O resultado são testes lentos, instáveis e pouco confiáveis.\u003c/p\u003e","title":"Testando Flow e StateFlow com Turbine em Kotlin | Kotlin Brasil"},{"content":"Sobre a vagaA Personetics busca uma pessoa Engenheira de QA Front-End de nível pleno para atuar em modelo híbrido, com opções em Giv'atayim, Tel Aviv, Nova York, Londres, Singapura ou São Paulo.\nResponsabilidadesPlanejar, executar e automatizar testes para aplicações web e mobile.Trabalhar com testes de interface, APIs, regressão visual, acessibilidade e qualidade em pipelines de CI.Colaborar com times de desenvolvimento em React, React Native, Kotlin e Swift.Registrar, acompanhar e comunicar defeitos usando ferramentas como YouTrack e Jira.RequisitosExperiência em QA Front-End e automação de testes.Conhecimento em Playwright, JavaScript, Appium, Detox, Espresso ou XCUITest.Experiência com testes de API usando Postman ou REST-assured.Familiaridade com Jenkins, Linux e ambientes em AWS.Conhecimento em acessibilidade com ferramentas como VoiceOver, TalkBack, JAWS ou NVDA.DiferenciaisExperiência com testes visuais usando Percy ou Applitools.Vivência em produtos mobile com Kotlin, Swift, React Native ou stacks híbridas. ","permalink":"https://kotlin.dev.br/vagas/0lm3i6sdcfgkcfxw-personetics-engenheiro-a-de-qa-front-end/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Personetics busca uma pessoa Engenheira de QA Front-End de nível pleno para atuar em modelo híbrido, com opções em Giv'atayim, Tel Aviv, Nova York, Londres, Singapura ou São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003ePlanejar, executar e automatizar testes para aplicações web e mobile.\u003c/li\u003e\u003cli\u003eTrabalhar com testes de interface, APIs, regressão visual, acessibilidade e qualidade em pipelines de CI.\u003c/li\u003e\u003cli\u003eColaborar com times de desenvolvimento em React, React Native, Kotlin e Swift.\u003c/li\u003e\u003cli\u003eRegistrar, acompanhar e comunicar defeitos usando ferramentas como YouTrack e Jira.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em QA Front-End e automação de testes.\u003c/li\u003e\u003cli\u003eConhecimento em Playwright, JavaScript, Appium, Detox, Espresso ou XCUITest.\u003c/li\u003e\u003cli\u003eExperiência com testes de API usando Postman ou REST-assured.\u003c/li\u003e\u003cli\u003eFamiliaridade com Jenkins, Linux e ambientes em AWS.\u003c/li\u003e\u003cli\u003eConhecimento em acessibilidade com ferramentas como VoiceOver, TalkBack, JAWS ou NVDA.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com testes visuais usando Percy ou Applitools.\u003c/li\u003e\u003cli\u003eVivência em produtos mobile com Kotlin, Swift, React Native ou stacks híbridas.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de QA Front-End"},{"content":"Sobre a vagaA Toast busca uma pessoa Engenheira de Software Principal para atuar no AI Pod, em posição de nível sênior e modelo híbrido em Dublin ou São Paulo.\nTecnologiasKotlin, Java, TypeScript e React.LLMs e ferramentas de desenvolvimento assistido por IA, como Claude Code, Cursor e GitHub Copilot.MCP (Model Context Protocol) e A2A (Agent-to-Agent).Observabilidade e acompanhamento com Langfuse e Datadog.RequisitosExperiência sênior em engenharia de software.Vivência com sistemas baseados em IA, LLMs ou ferramentas para produtividade de desenvolvimento.Capacidade de atuar em ambientes híbridos e colaborar com equipes distribuídas. ","permalink":"https://kotlin.dev.br/vagas/49gr4an109hv6mba-toast-engenheiro-a-de-software-principal-ai-pod/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Toast busca uma pessoa \u003cstrong\u003eEngenheira de Software Principal\u003c/strong\u003e para atuar no AI Pod, em posição de nível sênior e modelo híbrido em Dublin ou São Paulo.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java, TypeScript e React.\u003c/li\u003e\u003cli\u003eLLMs e ferramentas de desenvolvimento assistido por IA, como Claude Code, Cursor e GitHub Copilot.\u003c/li\u003e\u003cli\u003eMCP (Model Context Protocol) e A2A (Agent-to-Agent).\u003c/li\u003e\u003cli\u003eObservabilidade e acompanhamento com Langfuse e Datadog.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software.\u003c/li\u003e\u003cli\u003eVivência com sistemas baseados em IA, LLMs ou ferramentas para produtividade de desenvolvimento.\u003c/li\u003e\u003cli\u003eCapacidade de atuar em ambientes híbridos e colaborar com equipes distribuídas.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Principal - AI Pod"},{"content":"Sobre a vagaA Masabi busca uma pessoa Engenheiro(a) Principal para atuação remota a partir de Bogotá ou Colômbia.\nStack e contexto técnicoKotlin e JavaAPIs RESTAWS, DynamoDB e MySQLKafkaTerraformGitLab CI/CDSenioridadeVaga de nível sênior, com foco em liderança técnica e engenharia de software em sistemas de escala.\n","permalink":"https://kotlin.dev.br/vagas/41k9gg8d8m09cjzq-masabi-engenheiro-a-principal/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Masabi busca uma pessoa \u003cstrong\u003eEngenheiro(a) Principal\u003c/strong\u003e para atuação remota a partir de Bogotá ou Colômbia.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Java\u003c/li\u003e\u003cli\u003eAPIs REST\u003c/li\u003e\u003cli\u003eAWS, DynamoDB e MySQL\u003c/li\u003e\u003cli\u003eKafka\u003c/li\u003e\u003cli\u003eTerraform\u003c/li\u003e\u003cli\u003eGitLab CI/CD\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade\u003c/h3\u003e\u003cp\u003eVaga de nível sênior, com foco em liderança técnica e engenharia de software em sistemas de escala.\u003c/p\u003e","title":"Engenheiro(a) Principal"},{"content":"Sobre a vagaA Masabi busca um(a) Engenheiro(a) Principal de Payments para atuar remotamente em Bogotá ou na Colômbia, em uma posição sênior.\nTecnologiasKotlin e JavaAWSDynamoDB e MySQLTerraformGitLab CI/CDRequisitosExperiência em engenharia de software em nível sênior ou principal.Vivência com sistemas de pagamentos ou plataformas transacionais.Experiência com serviços em nuvem, bancos de dados e automação de infraestrutura.Capacidade de liderar decisões técnicas e colaborar com times de engenharia. ","permalink":"https://kotlin.dev.br/vagas/mn7mmqc1wv2zt5p8-masabi-engenheiro-a-principal-de-payments/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Masabi busca um(a) Engenheiro(a) Principal de Payments para atuar remotamente em Bogotá ou na Colômbia, em uma posição sênior.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Java\u003c/li\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eDynamoDB e MySQL\u003c/li\u003e\u003cli\u003eTerraform\u003c/li\u003e\u003cli\u003eGitLab CI/CD\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em engenharia de software em nível sênior ou principal.\u003c/li\u003e\u003cli\u003eVivência com sistemas de pagamentos ou plataformas transacionais.\u003c/li\u003e\u003cli\u003eExperiência com serviços em nuvem, bancos de dados e automação de infraestrutura.\u003c/li\u003e\u003cli\u003eCapacidade de liderar decisões técnicas e colaborar com times de engenharia.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) Principal de Payments"},{"content":"Sobre a vagaA TripleTen busca uma pessoa sênior para atuar como Especialista de Ensino em IA para QA em regime remoto e meio período.\nA posição é voltada a profissionais com experiência em QA, automação, uso de IA no ciclo de testes e orientação técnica de estudantes ou equipes.\nResponsabilidadesEnsinar e orientar conteúdos relacionados a IA aplicada à qualidade de software.Apoiar estudantes ou participantes no uso de ferramentas modernas de QA e automação.Conectar conceitos de testes, programação e fluxos agentivos em exemplos práticos.Contribuir com feedback técnico e boas práticas para evolução do aprendizado.RequisitosExperiência sênior em QA, automação de testes ou engenharia de software.Conhecimento em linguagens como Kotlin, Swift, Java, Python, JavaScript ou TypeScript.Familiaridade com ferramentas de IA e automação, como Cursor, testRigor, Magic Inspector ou Rainforest QA.Interesse em integrações do ecossistema MCP e workflows agentivos.Disponibilidade para trabalho remoto em meio período.LocalizaçãoVaga remota para pessoas em Boston, Estados Unidos, Israel, Europa, América do Sul ou América do Norte.\n","permalink":"https://kotlin.dev.br/vagas/hhie8pcy0yx5g2gk-tripleten-especialista-de-ensino-em-ia-para-qa-meio-periodo/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA TripleTen busca uma pessoa sênior para atuar como \u003cstrong\u003eEspecialista de Ensino em IA para QA\u003c/strong\u003e em regime remoto e meio período.\u003c/p\u003e\u003cp\u003eA posição é voltada a profissionais com experiência em QA, automação, uso de IA no ciclo de testes e orientação técnica de estudantes ou equipes.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eEnsinar e orientar conteúdos relacionados a IA aplicada à qualidade de software.\u003c/li\u003e\u003cli\u003eApoiar estudantes ou participantes no uso de ferramentas modernas de QA e automação.\u003c/li\u003e\u003cli\u003eConectar conceitos de testes, programação e fluxos agentivos em exemplos práticos.\u003c/li\u003e\u003cli\u003eContribuir com feedback técnico e boas práticas para evolução do aprendizado.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em QA, automação de testes ou engenharia de software.\u003c/li\u003e\u003cli\u003eConhecimento em linguagens como Kotlin, Swift, Java, Python, JavaScript ou TypeScript.\u003c/li\u003e\u003cli\u003eFamiliaridade com ferramentas de IA e automação, como Cursor, testRigor, Magic Inspector ou Rainforest QA.\u003c/li\u003e\u003cli\u003eInteresse em integrações do ecossistema MCP e workflows agentivos.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho remoto em meio período.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocalização\u003c/h3\u003e\u003cp\u003eVaga remota para pessoas em Boston, Estados Unidos, Israel, Europa, América do Sul ou América do Norte.\u003c/p\u003e","title":"Especialista de Ensino em IA para QA (Meio Período)"},{"content":"Acessibilidade em apps Android ainda é tratada por muitos times como acabamento visual, mas em 2026 ela virou parte central de qualidade, produto e empregabilidade. Bancos, varejo, saúde, educação, governo, mobilidade e plataformas B2B precisam atender pessoas que usam leitor de tela, fonte ampliada, navegação por teclado, controles externos, alto contraste ou apenas um celular antigo em uma situação ruim de luz. Quando o app falha nesse ponto, ele não fica apenas “menos bonito”: ele bloqueia uma parte real dos usuários.\nCom Kotlin e Jetpack Compose, acessibilidade ficou mais fácil de modelar porque a UI é declarativa e os componentes Material já carregam várias informações semânticas. Ao mesmo tempo, Compose não resolve tudo automaticamente. Um ícone sem contentDescription, uma área de toque pequena, uma ordem de foco confusa ou um texto que não cresce com a fonte do sistema continuam gerando experiências ruins. Para quem já estudou Jetpack Compose, MVVM com Kotlin e testes Android com Compose e Maestro, acessibilidade é o próximo passo para transformar telas funcionais em produto pronto para produção.\nEste guia mostra como pensar acessibilidade no Android moderno: descrições, semântica, TalkBack, foco, tamanhos de toque, formulários, estados de erro, testes automatizados e revisão manual. A ideia não é decorar uma lista de regras, mas criar um hábito técnico que melhora a experiência de todo mundo.\nO que acessibilidade significa em um app Android? Acessibilidade é a capacidade de uma pessoa usar o app mesmo quando ela não interage do jeito que o designer imaginou. Isso inclui deficiência visual, baixa visão, daltonismo, deficiência motora, deficiência auditiva, neurodivergência, idade avançada, lesão temporária, uso com uma mão, tela pequena, ambiente barulhento ou conexão ruim.\nNo Android, os recursos mais comuns envolvidos são:\nTalkBack e outros leitores de tela; tamanho de fonte e escala de exibição do sistema; navegação por teclado, D-pad ou switch access; contraste e modo escuro; feedback textual para erro, carregamento e sucesso; alvos de toque grandes o suficiente; estrutura semântica clara para componentes customizados. O ponto prático é simples: se a tela depende apenas de cor, posição visual, gesto delicado ou ícone sem texto, provavelmente existe um usuário que não consegue completar a tarefa.\nComece pela semântica correta Em Compose, a árvore visual não é exatamente a mesma coisa que a árvore de acessibilidade. Componentes como Button, TextField, Checkbox e Switch já expõem papéis úteis para tecnologias assistivas. O risco aparece quando criamos componentes customizados com Box, Row, Icon e Modifier.clickable sem informar o significado.\nUm card clicável de produto, por exemplo, precisa ser entendido como ação, não apenas como um agrupamento bonito:\n@Composable fun ProdutoCard( produto: Produto, onAbrir: () -\u0026gt; Unit, ) { Row( modifier = Modifier .fillMaxWidth() .clickable(onClickLabel = \u0026#34;Abrir detalhes de ${produto.nome}\u0026#34;) { onAbrir() } .semantics { role = Role.Button } .padding(16.dp), verticalAlignment = Alignment.CenterVertically, ) { Text(produto.nome, modifier = Modifier.weight(1f)) Text(produto.precoFormatado) } } O onClickLabel ajuda o leitor de tela a anunciar a intenção da ação. O role evita que um elemento interativo pareça apenas texto. Isso é especialmente importante em design systems próprios, onde muitos componentes são montados do zero.\ncontentDescription: quando usar e quando não usar contentDescription descreve imagens e ícones para usuários de leitor de tela. O erro comum é preencher tudo de forma mecânica. Nem toda imagem precisa ser anunciada. Se um ícone é puramente decorativo ao lado de um texto que já explica a ação, a descrição pode ser null. Se o ícone é a única indicação da ação, a descrição é obrigatória.\nIconButton(onClick = onFavoritar) { Icon( imageVector = Icons.Default.Favorite, contentDescription = \u0026#34;Favoritar artigo\u0026#34;, ) } Row(verticalAlignment = Alignment.CenterVertically) { Icon( imageVector = Icons.Default.Check, contentDescription = null, ) Text(\u0026#34;Pagamento confirmado\u0026#34;) } No primeiro caso, sem descrição, a pessoa ouviria algo genérico ou inútil. No segundo, anunciar “ícone de check” antes de “pagamento confirmado” só adicionaria ruído. A regra é perguntar: essa descrição ajuda a entender ou executar a tarefa?\nEvite também descrições que repetem o tipo visual: “botão de salvar” em um botão que já tem texto “Salvar” pode virar redundância. Prefira linguagem de ação: “Remover endereço”, “Abrir comprovante”, “Expandir detalhes da vaga”.\nEstados precisam ser anunciados Apps modernos têm loading, erro, vazio, atualização, filtro aplicado, item selecionado e operação pendente. Visualmente, o usuário percebe spinner, cor, skeleton ou badge. Para acessibilidade, esses estados precisam aparecer em texto, semântica ou anúncio.\nEm uma tela de lista, não basta trocar conteúdo silenciosamente depois de uma busca. Mostre estado textual e, quando necessário, use semântica para indicar que aquela região mudou:\n@Composable fun ResultadoBusca(status: BuscaStatus) { when (status) { BuscaStatus.Carregando -\u0026gt; Text( text = \u0026#34;Carregando resultados\u0026#34;, modifier = Modifier.semantics { liveRegion = LiveRegionMode.Polite }, ) is BuscaStatus.Erro -\u0026gt; Text( text = \u0026#34;Não foi possível carregar. Tente novamente.\u0026#34;, color = MaterialTheme.colorScheme.error, ) is BuscaStatus.Vazio -\u0026gt; Text(\u0026#34;Nenhum resultado encontrado para este filtro.\u0026#34;) is BuscaStatus.Sucesso -\u0026gt; Text(\u0026#34;${status.total} resultados encontrados\u0026#34;) } } Use liveRegion com moderação. Se tudo na tela anuncia mudança, o app vira uma sequência irritante de interrupções. Ele é útil para mensagens importantes que mudam sem uma ação direta visível, como resultado de busca, erro assíncrono ou confirmação crítica.\nTamanho de toque e espaçamento não são detalhe Um botão pequeno pode parecer elegante, mas ser impossível para quem tem tremor, usa uma mão no ônibus ou navega em tela compacta. O Material Design recomenda alvos de toque com pelo menos 48 dp. Em Compose, componentes Material geralmente respeitam isso, mas elementos customizados podem quebrar a regra facilmente.\nText( text = \u0026#34;Editar\u0026#34;, modifier = Modifier .minimumInteractiveComponentSize() .clickable { onEditar() } .padding(horizontal = 12.dp, vertical = 8.dp), ) Quando o layout está apertado, não reduza alvo de toque como primeira solução. Reorganize ações, use menu, aumente espaçamento ou transforme links críticos em botões claros. Um app profissional prioriza a tarefa, não apenas a densidade visual.\nTexto deve respeitar escala de fonte Muita tela Android quebra quando o usuário aumenta a fonte do sistema. Cards ficam cortados, botões perdem label, campos sobrepõem ícones e modais deixam ações fora da tela. Isso é comum quando o layout usa alturas fixas, linha única forçada ou componentes que não aceitam quebra.\nBoas práticas:\nevite altura fixa para componentes com texto; permita múltiplas linhas em títulos e descrições importantes; teste com fonte grande no emulador; não use sp minúsculo para “resolver” falta de espaço; prefira rolagem quando o conteúdo pode crescer; confirme que botões continuam legíveis em português, que costuma ter labels maiores. Se você cria design system, inclua estados com texto longo nas previews. Uma preview bonita com “OK” não prova que “Solicitar segunda via do comprovante” cabe no layout real.\nContraste, cor e feedback visual Cor ajuda, mas não pode ser a única fonte de informação. Um campo inválido que muda apenas de borda verde para vermelha não comunica o suficiente para pessoas com daltonismo, baixa visão ou leitor de tela. Combine cor com texto, ícone significativo e estado semântico.\nOutlinedTextField( value = email, onValueChange = onEmailChange, label = { Text(\u0026#34;E-mail\u0026#34;) }, isError = erroEmail != null, supportingText = { if (erroEmail != null) { Text(erroEmail) } }, ) Esse padrão é melhor que mostrar apenas uma borda vermelha. O texto de apoio explica o problema, aparece visualmente e pode ser anunciado pelo leitor de tela durante a navegação.\nTambém revise contraste em modo claro e escuro. Apps Android costumam ter bom contraste em textos principais, mas falham em placeholder, label desabilitada, badge, texto sobre imagem e chips selecionados.\nFormulários acessíveis em Kotlin Formulários são onde acessibilidade compra mais resultado de negócio. Cadastro, login, checkout, candidatura a vaga, agendamento e pagamento precisam ser completáveis por todos. Um formulário acessível tem labels claros, teclado correto, ordem de foco previsível, validação compreensível e erro perto do campo afetado.\nUse keyboardOptions para reduzir esforço:\nOutlinedTextField( value = telefone, onValueChange = onTelefoneChange, label = { Text(\u0026#34;Telefone\u0026#34;) }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Phone, imeAction = ImeAction.Next, ), ) Não use placeholder como substituto de label. Placeholder desaparece quando a pessoa digita e pode ser menos acessível. Também evite mensagens vagas como “campo inválido”. Explique: “Digite um e-mail com @ e domínio”, “A senha precisa ter pelo menos 8 caracteres”, “Selecione uma data futura”.\nOrdem de foco e navegação Quem usa TalkBack, teclado ou controles externos percorre a tela em ordem. Se a ordem semântica não combina com a ordem visual, a experiência fica confusa. Isso aparece em layouts com grids, cards complexos, banners promocionais e ações posicionadas fora do fluxo.\nEm Compose, a ordem natural geralmente segue a árvore de composição. Por isso, organize o código para refletir a leitura da tela. Se um botão aparece visualmente dentro de um card, mas no código fica em outro container distante, teste a navegação. Em alguns casos, agrupar semântica ajuda:\nColumn( modifier = Modifier.semantics(mergeDescendants = true) {} ) { Text(\u0026#34;Plano Pro\u0026#34;) Text(\u0026#34;R$ 49 por mês\u0026#34;) Text(\u0026#34;Inclui relatórios e suporte prioritário\u0026#34;) } mergeDescendants faz sentido quando vários textos formam uma única unidade de compreensão. Não use em excesso, porque pode esconder controles internos que deveriam ser navegáveis separadamente.\nTestes automatizados ajudam, mas não substituem uso real Compose UI Test permite validar semântica, texto e ações acessíveis. Isso evita regressões simples, especialmente em componentes reutilizáveis.\n@Test fun botaoFavoritarTemDescricaoAcessivel() { composeTestRule.setContent { ArtigoActions(onFavoritar = {}) } composeTestRule .onNodeWithContentDescription(\u0026#34;Favoritar artigo\u0026#34;) .assertExists() .assertHasClickAction() } Você também pode testar mensagens de erro, labels de formulário e estado vazio. Em um design system, crie testes para botões, campos, cards clicáveis, banners de alerta e componentes de navegação. Isso combina bem com testes de screenshot no Compose, mas lembre que screenshot valida pixels; acessibilidade valida intenção e interação.\nMesmo com testes, use TalkBack manualmente. Navegue pelo fluxo principal sem olhar para a tela. Tente abrir uma lista, filtrar, entrar em detalhe, corrigir erro e concluir uma ação. Esse exercício revela problemas que testes unitários não capturam.\nChecklist prático antes de publicar Antes de considerar uma tela pronta, valide:\ntodos os botões de ícone têm contentDescription útil ou null quando decorativos; cards clicáveis têm ação e papel semântico claros; textos importantes não cortam com fonte grande; campos têm label, teclado adequado e erro textual; mensagens de loading, vazio e erro são visíveis e compreensíveis; a ordem de foco segue a ordem visual; contraste funciona em modo claro e escuro; ações têm alvo de toque confortável; TalkBack consegue completar o fluxo principal; testes cobrem componentes acessíveis críticos. Para carreira, esse checklist também é uma ótima forma de diferenciar portfólio. Muitas pessoas mostram apps bonitos; poucas mostram apps que funcionam com fonte ampliada, leitor de tela e erro bem tratado.\nAcessibilidade e mercado Android no Brasil Acessibilidade aparece cada vez mais em vagas Android sênior porque empresas grandes não podem depender de telas frágeis. Apps financeiros, e-commerce, saúde, governo e educação precisam reduzir risco jurídico, melhorar conversão e atender públicos diversos. Saber falar sobre TalkBack, semântica, testes de UI e WCAG mostra maturidade além de “sei fazer tela em Compose”.\nEsse conhecimento também conversa com qualidade de engenharia. Um time que cuida de acessibilidade normalmente também cuida de Crashlytics e estabilidade, testes, design system, arquitetura e revisão de produto. Para comparar como outras comunidades tratam qualidade e experiência, vale observar o ecossistema de Python para automação e testes, que popularizou práticas de validação simples e repetíveis em times de produto.\nConclusão Acessibilidade no Android com Kotlin não é uma camada extra para o fim do projeto. Ela começa na escolha dos componentes, passa pela semântica do Compose, aparece em cada label de formulário e precisa ser verificada com testes e uso real. O melhor momento para corrigir um botão sem descrição é quando ele nasce, não depois que o app já virou uma coleção de exceções.\nUse componentes Material quando fizer sentido, descreva ações com clareza, preserve tamanho de toque, trate erro com texto, respeite escala de fonte e teste com TalkBack. Esses cuidados deixam o app melhor para pessoas com deficiência e também para qualquer usuário em contexto difícil. Em 2026, um app Android profissional não é apenas rápido, bonito e escrito em Kotlin idiomático. Ele também é possível de usar.\n","permalink":"https://kotlin.dev.br/blog/acessibilidade-android-compose-kotlin-2026/","summary":"\u003cp\u003eAcessibilidade em apps Android ainda é tratada por muitos times como acabamento visual, mas em 2026 ela virou parte central de qualidade, produto e empregabilidade. Bancos, varejo, saúde, educação, governo, mobilidade e plataformas B2B precisam atender pessoas que usam leitor de tela, fonte ampliada, navegação por teclado, controles externos, alto contraste ou apenas um celular antigo em uma situação ruim de luz. Quando o app falha nesse ponto, ele não fica apenas “menos bonito”: ele bloqueia uma parte real dos usuários.\u003c/p\u003e","title":"Acessibilidade no Android com Kotlin e Compose em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA Hiflylabs busca um(a) Desenvolvedor(a) Fullstack Sênior para atuar em contrato no desenvolvimento de aplicações com Databricks Apps. A posição é remota e considera profissionais em Blumenau ou na Hungria.\nResponsabilidadesDesenvolver e manter aplicações fullstack integradas ao ecossistema Databricks.Trabalhar com APIs REST, bancos de dados e pipelines de desenvolvimento.Colaborar com times técnicos em entregas de backend, frontend e automação.Contribuir para boas práticas de versionamento, CI/CD e operação em ambientes cloud.RequisitosExperiência sênior em desenvolvimento fullstack.Conhecimento em Kotlin, Java, Python ou Node.js.Experiência com Angular ou React.Vivência com Databricks, SQLAlchemy e APIs REST.Conhecimento em Docker, GitHub Actions ou Azure DevOps.Familiaridade com ambientes Linux/Unix.Modelo de trabalhoContrato.Trabalho remoto.Localidade: Blumenau ou Hungria. ","permalink":"https://kotlin.dev.br/vagas/sabhz5emcks802i5-hiflylabs-desenvolvedor-a-fullstack-senior-databricks-apps-cont/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Hiflylabs busca um(a) Desenvolvedor(a) Fullstack Sênior para atuar em contrato no desenvolvimento de aplicações com Databricks Apps. A posição é remota e considera profissionais em Blumenau ou na Hungria.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações fullstack integradas ao ecossistema Databricks.\u003c/li\u003e\u003cli\u003eTrabalhar com APIs REST, bancos de dados e pipelines de desenvolvimento.\u003c/li\u003e\u003cli\u003eColaborar com times técnicos em entregas de backend, frontend e automação.\u003c/li\u003e\u003cli\u003eContribuir para boas práticas de versionamento, CI/CD e operação em ambientes cloud.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento fullstack.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Java, Python ou Node.js.\u003c/li\u003e\u003cli\u003eExperiência com Angular ou React.\u003c/li\u003e\u003cli\u003eVivência com Databricks, SQLAlchemy e APIs REST.\u003c/li\u003e\u003cli\u003eConhecimento em Docker, GitHub Actions ou Azure DevOps.\u003c/li\u003e\u003cli\u003eFamiliaridade com ambientes Linux/Unix.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eContrato.\u003c/li\u003e\u003cli\u003eTrabalho remoto.\u003c/li\u003e\u003cli\u003eLocalidade: Blumenau ou Hungria.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Fullstack Sênior - Databricks Apps (Contrato)"},{"content":"Sobre a vagaA CI\u0026amp;T busca uma pessoa Desenvolvedora Java Pleno para atuação remota, com base em Campinas ou em qualquer local do Brasil.\nResponsabilidadesDesenvolver e manter aplicações backend com Java, Kotlin e Spring Boot.Trabalhar com APIs, serviços reativos e integrações usando Reactor e WebFlux.Colaborar com times multidisciplinares em entregas com Git, CI/CD e Docker.Apoiar observabilidade e operação de sistemas com ELK Stack e Datadog.RequisitosExperiência em desenvolvimento backend com Java.Conhecimento em Kotlin, Spring Boot, Reactor ou WebFlux.Vivência com bancos de dados como MongoDB, PostgreSQL ou Oracle.Familiaridade com Git, pipelines de CI/CD e Docker.DiferenciaisExperiência com Node.js, React ou Angular.Conhecimento em Lambdas e arquiteturas orientadas a eventos. ","permalink":"https://kotlin.dev.br/vagas/kmj74k9keuyu110o-ci-t-desenvolvedor-a-java-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026amp;T busca uma pessoa Desenvolvedora Java Pleno para atuação remota, com base em Campinas ou em qualquer local do Brasil.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações backend com Java, Kotlin e Spring Boot.\u003c/li\u003e\u003cli\u003eTrabalhar com APIs, serviços reativos e integrações usando Reactor e WebFlux.\u003c/li\u003e\u003cli\u003eColaborar com times multidisciplinares em entregas com Git, CI/CD e Docker.\u003c/li\u003e\u003cli\u003eApoiar observabilidade e operação de sistemas com ELK Stack e Datadog.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento backend com Java.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Spring Boot, Reactor ou WebFlux.\u003c/li\u003e\u003cli\u003eVivência com bancos de dados como MongoDB, PostgreSQL ou Oracle.\u003c/li\u003e\u003cli\u003eFamiliaridade com Git, pipelines de CI/CD e Docker.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Node.js, React ou Angular.\u003c/li\u003e\u003cli\u003eConhecimento em Lambdas e arquiteturas orientadas a eventos.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Java Pleno"},{"content":"Sobre a vagaA CI\u0026amp;T busca uma pessoa Desenvolvedora Java Sênior para atuação remota no Brasil, com referência de localização em Campinas.\nA vaga envolve um stack backend com Java, Kotlin, Spring Boot, Reactor e WebFlux, além de integração com bancos relacionais e NoSQL.\nTecnologias mencionadasJava, Kotlin, Spring Boot, Reactor e WebFluxNode.js, React e AngularMongoDB, PostgreSQL e OracleGit, CI/CD, Docker, ELK e DatadogLambdasSenioridadeNível sênior.\nLocal de trabalhoVaga remota, aberta para Campinas ou demais localidades no Brasil.\n","permalink":"https://kotlin.dev.br/vagas/cfqtjhylh0ck47ga-ci-t-desenvolvedor-a-java-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026amp;T busca uma pessoa Desenvolvedora Java Sênior para atuação remota no Brasil, com referência de localização em Campinas.\u003c/p\u003e\u003cp\u003eA vaga envolve um stack backend com Java, Kotlin, Spring Boot, Reactor e WebFlux, além de integração com bancos relacionais e NoSQL.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eJava, Kotlin, Spring Boot, Reactor e WebFlux\u003c/li\u003e\u003cli\u003eNode.js, React e Angular\u003c/li\u003e\u003cli\u003eMongoDB, PostgreSQL e Oracle\u003c/li\u003e\u003cli\u003eGit, CI/CD, Docker, ELK e Datadog\u003c/li\u003e\u003cli\u003eLambdas\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade\u003c/h3\u003e\u003cp\u003eNível sênior.\u003c/p\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota, aberta para Campinas ou demais localidades no Brasil.\u003c/p\u003e","title":"Desenvolvedor(a) Java Sênior"},{"content":"Sobre a vagaO iFood busca uma Engenheira de Software Backend Sênior para uma vaga afirmativa para mulheres. A posição é presencial e tem localização informada como Osasco ou Brasil.\nTecnologiasKotlin, Java e RustAWS, SQS, SNS, RabbitMQ e KafkaKubernetes, Docker, Terraform e HelmLinux e DatabricksPerfilSenioridade: nível sênior.Experiência em desenvolvimento Backend e sistemas distribuídos.Vivência com mensageria, infraestrutura em nuvem e ambientes conteinerizados. ","permalink":"https://kotlin.dev.br/vagas/kufaleubeqrbb2xg-ifood-engenheira-backend-senior-afirmativa-para-mulheres/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma Engenheira de Software Backend Sênior para uma vaga afirmativa para mulheres. A posição é presencial e tem localização informada como Osasco ou Brasil.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java e Rust\u003c/li\u003e\u003cli\u003eAWS, SQS, SNS, RabbitMQ e Kafka\u003c/li\u003e\u003cli\u003eKubernetes, Docker, Terraform e Helm\u003c/li\u003e\u003cli\u003eLinux e Databricks\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cul\u003e\u003cli\u003eSenioridade: nível sênior.\u003c/li\u003e\u003cli\u003eExperiência em desenvolvimento Backend e sistemas distribuídos.\u003c/li\u003e\u003cli\u003eVivência com mensageria, infraestrutura em nuvem e ambientes conteinerizados.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheira Backend Sênior (afirmativa para mulheres)"},{"content":"Sobre a vagaA Engine busca uma pessoa Engenheira de Software Fullstack Sênior para atuação remota na América do Norte ou América do Sul.\nStack e contexto técnicoDesenvolvimento fullstack com TypeScript, React e Ruby on Rails.Ambiente com AWS, incluindo ECS e Lambda.Uso de tecnologias como Kotlin, Java, NoSQL, Amplitude, Nexus e Slack.RequisitosExperiência sênior em engenharia de software.Vivência com desenvolvimento de aplicações web fullstack.Capacidade de trabalhar de forma remota com times distribuídos nas Américas. ","permalink":"https://kotlin.dev.br/vagas/yaksb4dwcxlfihpn-engine-engenheiro-a-de-software-fullstack-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Engine busca uma pessoa Engenheira de Software Fullstack Sênior para atuação remota na América do Norte ou América do Sul.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolvimento fullstack com \u003cstrong\u003eTypeScript\u003c/strong\u003e, \u003cstrong\u003eReact\u003c/strong\u003e e \u003cstrong\u003eRuby on Rails\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eAmbiente com \u003cstrong\u003eAWS\u003c/strong\u003e, incluindo ECS e Lambda.\u003c/li\u003e\u003cli\u003eUso de tecnologias como \u003cstrong\u003eKotlin\u003c/strong\u003e, \u003cstrong\u003eJava\u003c/strong\u003e, NoSQL, Amplitude, Nexus e Slack.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software.\u003c/li\u003e\u003cli\u003eVivência com desenvolvimento de aplicações web fullstack.\u003c/li\u003e\u003cli\u003eCapacidade de trabalhar de forma remota com times distribuídos nas Américas.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Fullstack Sênior"},{"content":"Sobre a vagaO C6 Bank busca uma Pessoa Desenvolvedora Android Pleno para atuar em prevenção a fraudes, com foco em desenvolvimento mobile Android usando Kotlin.\nModelo de trabalho presencial. Localização informada: São Paulo ou Brasil.\nResponsabilidadesDesenvolver e manter funcionalidades Android para produtos ligados à prevenção a fraudes.Construir interfaces e fluxos mobile com Kotlin, Jetpack Compose e Android SDK.Integrar aplicações Android a APIs RESTful.Aplicar boas práticas de arquitetura, como Clean Architecture e MVVM.Trabalhar com Coroutines, Flow, Lifecycle, ViewModel e LiveData.Participar de rotinas ágeis com Scrum ou Kanban.Colaborar com versionamento em Git, pipelines de CI/CD e publicação na Google Play Store.RequisitosExperiência profissional com desenvolvimento Android.Conhecimento em Kotlin e Android SDK.Experiência com Jetpack Compose.Conhecimento em consumo de APIs RESTful.Experiência com Coroutines, Flow, ViewModel, Lifecycle e LiveData.Familiaridade com Clean Architecture e MVVM.Conhecimento em Git e práticas de CI/CD.DiferenciaisExperiência com publicação e manutenção de aplicativos na Google Play Store.Vivência em times ágeis usando Scrum ou Kanban.Experiência em produtos financeiros, segurança ou prevenção a fraudes. ","permalink":"https://kotlin.dev.br/vagas/ehflv8bsm7cctfwo-c6-bank-pessoa-desenvolvedora-android-pleno-prevencao-a-fraudes/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma Pessoa Desenvolvedora Android Pleno para atuar em prevenção a fraudes, com foco em desenvolvimento mobile Android usando Kotlin.\u003c/p\u003e\u003cp\u003eModelo de trabalho presencial. Localização informada: São Paulo ou Brasil.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter funcionalidades Android para produtos ligados à prevenção a fraudes.\u003c/li\u003e\u003cli\u003eConstruir interfaces e fluxos mobile com Kotlin, Jetpack Compose e Android SDK.\u003c/li\u003e\u003cli\u003eIntegrar aplicações Android a APIs RESTful.\u003c/li\u003e\u003cli\u003eAplicar boas práticas de arquitetura, como Clean Architecture e MVVM.\u003c/li\u003e\u003cli\u003eTrabalhar com Coroutines, Flow, Lifecycle, ViewModel e LiveData.\u003c/li\u003e\u003cli\u003eParticipar de rotinas ágeis com Scrum ou Kanban.\u003c/li\u003e\u003cli\u003eColaborar com versionamento em Git, pipelines de CI/CD e publicação na Google Play Store.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência profissional com desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin e Android SDK.\u003c/li\u003e\u003cli\u003eExperiência com Jetpack Compose.\u003c/li\u003e\u003cli\u003eConhecimento em consumo de APIs RESTful.\u003c/li\u003e\u003cli\u003eExperiência com Coroutines, Flow, ViewModel, Lifecycle e LiveData.\u003c/li\u003e\u003cli\u003eFamiliaridade com Clean Architecture e MVVM.\u003c/li\u003e\u003cli\u003eConhecimento em Git e práticas de CI/CD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com publicação e manutenção de aplicativos na Google Play Store.\u003c/li\u003e\u003cli\u003eVivência em times ágeis usando Scrum ou Kanban.\u003c/li\u003e\u003cli\u003eExperiência em produtos financeiros, segurança ou prevenção a fraudes.\u003c/li\u003e\u003c/ul\u003e","title":"Pessoa Desenvolvedora Android Pleno | Prevenção a Fraudes"},{"content":"Sobre a vagaO iFood busca uma pessoa Staff Software Engineer Backend para atuar em projetos com Kotlin, Java e machine learning.\nRequisitosExperiência sênior em engenharia de software backend.Experiência com Kotlin e Java.Conhecimento ou experiência em machine learning.Local de trabalhoAtuação presencial em Osasco ou Brasil.\n","permalink":"https://kotlin.dev.br/vagas/yldek3ce1isklxef-ifood-staff-software-engineer-backend/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa Staff Software Engineer Backend para atuar em projetos com Kotlin, Java e machine learning.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software backend.\u003c/li\u003e\u003cli\u003eExperiência com Kotlin e Java.\u003c/li\u003e\u003cli\u003eConhecimento ou experiência em machine learning.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eAtuação presencial em Osasco ou Brasil.\u003c/p\u003e","title":"Staff Software Engineer Backend"},{"content":"O suporte oficial de Kotlin para Visual Studio Code entrou no radar de muita gente em 2026. Para uma linguagem historicamente associada ao IntelliJ IDEA e ao Android Studio, isso muda a conversa: agora existe um caminho mais claro para quem trabalha em monorepos, projetos backend pequenos, automações, APIs e times que já usam VS Code como editor principal.\nMas a pergunta prática não é \u0026ldquo;VS Code substitui o IntelliJ?\u0026rdquo;. A pergunta melhor é: em quais cenários vale usar Kotlin no VS Code, quais limites você precisa aceitar e como montar um fluxo que não atrapalhe o projeto?\nEste guia responde com foco em pessoas desenvolvedoras brasileiras que estão avaliando Kotlin para backend, ferramentas internas, migração de Java ou aprendizado. Se o seu objetivo é Android pesado, Compose ou profiling avançado, a resposta pode ser diferente.\nO que mudou para Kotlin no VS Code? Até pouco tempo atrás, usar Kotlin no VS Code era possível, mas frequentemente irregular. Você dependia de extensões comunitárias, configuração manual de linguagem, Gradle rodando no terminal e pouca integração real com o compilador.\nCom o movimento oficial da JetBrains em torno de uma extensão Kotlin para VS Code, a experiência fica mais séria para tarefas como:\nabrir projetos Kotlin sem trocar imediatamente de editor; editar código com suporte de linguagem mais consistente; experimentar Kotlin em ambientes onde VS Code já é padrão; trabalhar em repositórios mistos com Kotlin, JavaScript, Python, YAML, Terraform e documentação; reduzir a barreira de entrada para quem está vindo de Java ou backend web. Isso não elimina o papel do IntelliJ IDEA. Ele continua sendo a referência para refatorações profundas, navegação complexa, integração Gradle madura e produtividade diária em bases grandes. O ponto é que Kotlin deixa de parecer uma linguagem presa a uma única IDE.\nQuando VS Code faz sentido para Kotlin? VS Code pode ser uma boa escolha quando o projeto Kotlin é enxuto, quando o repositório é poliglota ou quando você quer aprender a linguagem sem mudar todo o ambiente de trabalho.\nExemplos realistas:\numa API pequena em Ktor ou Spring Boot com Kotlin; scripts .kts para automação local; bibliotecas JVM internas com poucos módulos; exercícios de linguagem, coleções, null safety e testes; manutenção pontual em um monorepo onde Kotlin é apenas uma parte; revisão de código Kotlin em times que usam VS Code no restante da stack. Também faz sentido para quem está comparando Kotlin com outras linguagens modernas. Se você já está avaliando Kotlin vs Java em 2026, testar Kotlin no editor atual pode diminuir o atrito inicial.\nQuando preferir IntelliJ IDEA ou Android Studio? Para muitos projetos profissionais, especialmente no começo de 2026, IntelliJ IDEA e Android Studio continuam sendo escolhas mais seguras.\nPrefira IntelliJ IDEA quando você precisa de:\nrefatorações grandes entre módulos; inspeções Kotlin e Java mais completas; navegação profunda em projetos Gradle complexos; integração forte com testes, cobertura e debugging; produtividade alta em Kotlin para backend; suporte mais maduro para KSP, annotation processing e plugins. Prefira Android Studio quando o projeto envolve:\nAndroid nativo; Jetpack Compose; previews de interface; emulador, Logcat, profiler e ferramentas do Android SDK; Hilt, Room, Navigation, WorkManager e testes instrumentados; publicação, signing e diagnóstico de builds Android. O VS Code pode abrir e editar arquivos Android, mas isso não significa que ele seja o melhor ambiente para desenvolver um app Android completo. Para esse cenário, veja também o guia de desenvolvimento Android com Kotlin e o artigo sobre Hilt no Android com Kotlin.\nSetup mínimo recomendado Para evitar uma experiência frustrante, não comece apenas instalando uma extensão e abrindo uma pasta qualquer. Monte um fluxo mínimo e verificável.\n1. Instale JDK e Gradle wrapper Projetos Kotlin reais normalmente devem usar o Gradle Wrapper do próprio repositório:\n./gradlew --version Isso confirma qual versão de Gradle, JVM e Kotlin Gradle Plugin o projeto usa. Em times brasileiros, esse detalhe evita o clássico \u0026ldquo;funciona na minha máquina\u0026rdquo; quando uma pessoa usa JDK 17, outra JDK 21 e outra JDK 24 sem perceber.\n2. Abra a raiz correta do projeto Abra no VS Code a pasta onde ficam settings.gradle.kts, build.gradle.kts ou gradlew. Se você abrir uma subpasta isolada, a extensão pode não enxergar corretamente os módulos.\nUm projeto simples pode ter este formato:\nmeu-servico-kotlin/ gradlew settings.gradle.kts build.gradle.kts src/ main/kotlin/br/dev/Servico.kt test/kotlin/br/dev/ServicoTest.kt Em monorepos, vale criar uma workspace do VS Code apontando para a parte Kotlin e os arquivos compartilhados relevantes, em vez de abrir um repositório gigantesco sem critério.\n3. Use o terminal como fonte de verdade Mesmo com suporte de IDE, mantenha os comandos de build explícitos:\n./gradlew test ./gradlew build Se o editor diz que está tudo certo, mas ./gradlew build falha, o build está falhando. Para projetos de backend, esse hábito combina bem com os guias de CI/CD com Kotlin e Gradle em Kotlin.\nExemplo: projeto Kotlin JVM pequeno Um build.gradle.kts mínimo para estudos ou ferramenta interna pode começar assim:\nplugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.2.0\u0026#34; application } repositories { mavenCentral() } dependencies { testImplementation(kotlin(\u0026#34;test\u0026#34;)) } application { mainClass.set(\u0026#34;br.dev.MainKt\u0026#34;) } E um arquivo Main.kt:\npackage br.dev fun main() { val linguagens = listOf(\u0026#34;Kotlin\u0026#34;, \u0026#34;Java\u0026#34;, \u0026#34;TypeScript\u0026#34;) linguagens .filter { it.startsWith(\u0026#34;K\u0026#34;) } .forEach { println(\u0026#34;Estudando $it\u0026#34;) } } No VS Code, a edição deve ser confortável. No terminal, a validação continua simples:\n./gradlew run ./gradlew test Esse tipo de projeto é uma boa porta de entrada para aprender collections em Kotlin, funções de extensão e null safety sem carregar todo o peso de um app Android.\nCuidado com projetos Kotlin Multiplatform Kotlin Multiplatform é um caso especial. Mesmo quando o código comum parece simples, o projeto pode envolver alvos JVM, Android, iOS, desktop, web ou Wasm. Isso aumenta a dependência de Gradle, plugins e tarefas específicas.\nVS Code pode ajudar na edição, mas a decisão precisa considerar:\nquantos targets o projeto compila; se há código iOS com CocoaPods, Swift Package Manager ou Xcode; se há Compose Multiplatform; se a equipe depende de previews, refatorações e depuração por target; se o build local roda com estabilidade no terminal. Para entender melhor esse cenário, leia também Kotlin Multiplatform, nova estrutura de projetos KMP e Compose Multiplatform para iOS em produção.\nFluxo recomendado para times Se sua equipe quer adotar Kotlin no VS Code, trate isso como decisão de fluxo, não como preferência pessoal de editor.\nUm caminho seguro:\nDefina JDK, Gradle Wrapper e versão Kotlin no repositório. Documente os comandos mínimos: test, build, run e lint quando existir. Valide se a extensão atende navegação, autocomplete e diagnósticos básicos. Mantenha IntelliJ IDEA ou Android Studio como fallback para refatorações grandes. Evite misturar migração de editor com migração de arquitetura. O erro comum é tentar resolver tudo ao mesmo tempo: migrar Java para Kotlin, trocar IDE, alterar build, mudar arquitetura e introduzir coroutines na mesma semana. Faça em etapas.\nSe o objetivo é migração, comece pelo artigo sobre converter Java para Kotlin no VS Code e depois aprofunde em Kotlin para desenvolvedores Java.\nChecklist rápido Antes de apostar em VS Code para um projeto Kotlin, responda:\nO projeto compila com ./gradlew build sem depender da IDE? A equipe sabe qual JDK usar? Os módulos Kotlin são pequenos o suficiente para navegação confortável? As refatorações principais já foram feitas ou ainda estão por vir? Há Android, Compose ou Multiplatform complexo envolvido? Existe fallback claro para IntelliJ IDEA ou Android Studio? Se a maioria das respostas favorece simplicidade, VS Code pode ser uma opção prática. Se o projeto é grande, Android-heavy ou cheio de plugins, comece pelo ambiente JetBrains e use VS Code como apoio.\nConclusão Kotlin no VS Code em 2026 é uma oportunidade real para ampliar o alcance da linguagem, principalmente em backend, automação, aprendizado e repositórios poliglotas. A novidade é importante porque reduz atrito, não porque torna as IDEs JetBrains irrelevantes.\nPara uma pessoa desenvolvedora brasileira, a melhor decisão é pragmática: use VS Code quando ele acelerar o trabalho sem esconder problemas de build; use IntelliJ IDEA ou Android Studio quando o projeto exigir refatoração, Android, Compose, Gradle complexo ou depuração mais profunda.\nKotlin fica mais forte quando você escolhe a ferramenta pelo contexto do projeto, não pela torcida por um editor.\n","permalink":"https://kotlin.dev.br/blog/kotlin-vscode-alpha-guia-pratico-2026/","summary":"\u003cp\u003eO suporte oficial de Kotlin para Visual Studio Code entrou no radar de muita gente em 2026. Para uma linguagem historicamente associada ao IntelliJ IDEA e ao Android Studio, isso muda a conversa: agora existe um caminho mais claro para quem trabalha em monorepos, projetos backend pequenos, automações, APIs e times que já usam VS Code como editor principal.\u003c/p\u003e\n\u003cp\u003eMas a pergunta prática não é \u0026ldquo;VS Code substitui o IntelliJ?\u0026rdquo;. A pergunta melhor é: \u003cstrong\u003eem quais cenários vale usar Kotlin no VS Code, quais limites você precisa aceitar e como montar um fluxo que não atrapalhe o projeto?\u003c/strong\u003e\u003c/p\u003e","title":"Kotlin no VS Code em 2026: guia prático para usar sem abandonar o ecossistema JetBrains | Kotlin Brasil"},{"content":"Qual a melhor IDE para programar em Kotlin? A escolha da IDE certa pode fazer uma diferença enorme na sua produtividade como desenvolvedor Kotlin. A resposta direta é: IntelliJ IDEA é a melhor IDE para Kotlin de uso geral, e Android Studio é a melhor para desenvolvimento Android. Mas existem outras opções válidas dependendo do seu contexto. Vamos analisar cada uma em profundidade.\nIntelliJ IDEA: a referência para Kotlin IntelliJ IDEA, desenvolvida pela JetBrains (a mesma empresa que criou o Kotlin), é a IDE com o melhor suporte para a linguagem. Isso não é coincidência: o plugin de Kotlin foi desenvolvido em conjunto com a IDE, garantindo integração profunda e funcionalidades exclusivas.\nIntelliJ IDEA Community Edition (gratuita):\nSuporte completo para Kotlin/JVM Refatoração avançada Auto-complete inteligente Depuração integrada Suporte a Gradle e Maven Inspeções de código e sugestões de melhoria IntelliJ IDEA Ultimate (paga):\nTudo da Community Edition Suporte a frameworks web (Ktor, Spring Boot) Ferramentas de banco de dados integradas Suporte a JavaScript e TypeScript Profiling e monitoramento // IntelliJ oferece sugestões inteligentes enquanto você digita // Por exemplo, ao escrever este código, a IDE sugere: data class Configuração( val servidor: String, val porta: Int = 8080, val debug: Boolean = false ) fun main() { // A IDE sugere automaticamente os parâmetros nomeados val config = Configuração( servidor = \u0026#34;localhost\u0026#34;, porta = 3000, debug = true ) // Auto-complete mostra todas as propriedades e funções disponíveis println(\u0026#34;Conectando a ${config.servidor}:${config.porta}\u0026#34;) // A IDE detecta código que pode ser simplificado // e sugere refatorações automaticamente val lista = listOf(1, 2, 3, 4, 5) val pares = lista.filter { it % 2 == 0 } val soma = pares.sum() println(\u0026#34;Soma dos pares: $soma\u0026#34;) } Android Studio: essencial para mobile Android Studio é baseado no IntelliJ IDEA e é a IDE oficial para desenvolvimento Android. Se você trabalha com Android, não há alternativa melhor.\nRecursos exclusivos para Android:\nEmulador de dispositivos Android integrado Layout Editor para Jetpack Compose com preview em tempo real Profiler de CPU, memória e rede App Inspection para banco de dados e network Assistente de migração para novas versões do Android // Preview de Composable diretamente na IDE @Preview(showBackground = true, name = \u0026#34;Preview do Cartao\u0026#34;) @Composable fun CartaoPreview() { MaterialTheme { CartaoInformacao( titulo = \u0026#34;Kotlin Brasil\u0026#34;, descricao = \u0026#34;Comunidade brasileira de Kotlin\u0026#34;, destaque = true ) } } @Composable fun CartaoInformacao( titulo: String, descricao: String, destaque: Boolean = false ) { Card( modifier = Modifier .fillMaxWidth() .padding(16.dp), colors = CardDefaults.cardColors( containerColor = if (destaque) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.surface ) ) { Column(modifier = Modifier.padding(16.dp)) { Text(text = titulo, style = MaterialTheme.typography.titleLarge) Spacer(modifier = Modifier.height(8.dp)) Text(text = descricao, style = MaterialTheme.typography.bodyMedium) } } } VS Code com suporte oficial Kotlin Alpha Visual Studio Code deixou de ser apenas uma opção comunitária para Kotlin. Em 2026, a JetBrains anunciou o Kotlin by JetBrains para VS Code, uma extensão oficial em Alpha baseada no Kotlin Language Server. Isso muda a resposta para quem usa monorepos, trabalha em times poliglotas ou quer editar Kotlin sem abrir uma IDE pesada.\nAinda assim, Alpha não significa paridade completa com IntelliJ. Use VS Code quando o projeto é leve, quando você alterna entre várias linguagens ou quando precisa revisar scripts e módulos pequenos. Para Android, migrações grandes de Java para Kotlin, refatorações profundas e investigação de build Gradle, IntelliJ IDEA e Android Studio continuam mais seguros.\nVantagens:\nLeve e rápido para iniciar Gratuito e de código aberto Extensão oficial da JetBrains em Alpha Suporte via Kotlin Language Server para recursos básicos de editor Bom para edições rápidas, scripts e projetos pequenos Útil em repositórios com Kotlin, JavaScript, Python, YAML e infraestrutura no mesmo workspace Limitações:\nAinda é Alpha, então espere bugs e lacunas Auto-complete e refatoração ainda ficam atrás do IntelliJ Sem depuração integrada para Kotlin/JVM (sem configuração adicional) Menos inspeções avançadas de código, Gradle e Android Se você está começando em Kotlin, comece pelo IntelliJ IDEA Community. Se você já vive no VS Code e quer experimentar Kotlin, a extensão oficial reduz o atrito inicial.\nFleet: a nova opção da JetBrains Fleet é o editor mais recente da JetBrains, projetado como uma alternativa leve ao IntelliJ. Pode funcionar como um editor simples ou ativar o modo \u0026ldquo;Smart Mode\u0026rdquo; para obter funcionalidades de IDE completa.\nCaracterísticas:\nInicialização mais rápida que IntelliJ Modo leve para edições rápidas Smart Mode com funcionalidades completas de IDE Interface moderna e limpa Comparação detalhada Recurso IntelliJ Community IntelliJ Ultimate Android Studio VS Code Auto-complete Kotlin Excelente Excelente Excelente Em evolução Refatoração Completa Completa Completa Limitada/Alpha Debug Completo Completo Completo Configurável Uso de memória Alto Alto Muito alto Baixo Velocidade de início Lenta Lenta Lenta Rápida Suporte a Spring Básico Completo Não Limitado Android tools Não Parcial Completo Não Preço Grátis Pago Grátis Grátis Pros e contras de cada IDE IntelliJ IDEA Community:\nPro: melhor suporte Kotlin gratuito disponivel Pro: refatoração e inspecoes de nível profissional Pro: integração perfeita com Gradle Contra: consumo alto de memória Contra: lenta para iniciar Android Studio:\nPro: indispensavel para desenvolvimento Android Pro: emulador e ferramentas de profiling Pro: preview de Jetpack Compose Contra: muito pesado (consome muita RAM) Contra: desnecessário se você não desenvolve para Android VS Code:\nPro: leve e rápido Pro: agora tem suporte oficial Alpha da JetBrains Pro: ótimo para scripts, projetos pequenos e repositórios poliglotas Contra: suporte Kotlin ainda inferior ao IntelliJ em projetos grandes Contra: depuração e Gradle exigem mais configuração Configurações recomendadas Para aproveitar ao máximo sua IDE com Kotlin, considere estas configurações:\nMínimo recomendado de hardware:\n8 GB de RAM (16 GB ideal para Android Studio) SSD (obrigatório para performance aceitável) Processador quad-core ou superior Plugins essenciais para IntelliJ/Android Studio:\nKotlin (já incluso) Detekt: análise estática de código Kotlin Rainbow Brackets: colorização de chaves e parênteses Key Promoter X: aprenda atalhos de teclado GitToolBox: informações do Git na IDE Atalhos de teclado essenciais Conhecer os atalhos mais importantes acelera muito seu trabalho diário:\nShift + Shift: buscar qualquer coisa (arquivo, classe, ação) Ctrl + Shift + A (Cmd + Shift + A no Mac): buscar ações Alt + Enter: mostrar sugestões e quick fixes Ctrl + B (Cmd + B): ir para definição Ctrl + Shift + R (Cmd + Shift + R): substituir em arquivos Ctrl + Alt + L (Cmd + Alt + L): reformatar código Qual escolher? A recomendação é simples:\nDesenvolvimento Android: use Android Studio, sem alternativa Backend ou projetos gerais: IntelliJ IDEA Community Edition Projetos web fullstack ou Spring Boot profissional: IntelliJ IDEA Ultimate Edições rápidas, scripts ou repositórios poliglotas: VS Code com Kotlin by JetBrains Alpha ou Fleet Estudante ou iniciante: IntelliJ IDEA Community Edition (grátis e completa) Independente da IDE escolhida, o mais importante é conhecê-la bem. Invista tempo aprendendo atalhos, configurações e plugins. Uma IDE bem dominada multiplica sua produtividade de forma significativa.\nPerguntas relacionadas Como instalar Kotlin Como praticar Kotlin? Kotlin vale a pena em 2026? Como aprender Kotlin em 2026? Apps desktop com Kotlin ","permalink":"https://kotlin.dev.br/perguntas/melhor-ide-kotlin/","summary":"\u003ch2 id=\"qual-a-melhor-ide-para-programar-em-kotlin\"\u003eQual a melhor IDE para programar em Kotlin?\u003c/h2\u003e\n\u003cp\u003eA escolha da IDE certa pode fazer uma diferença enorme na sua produtividade como desenvolvedor Kotlin. A resposta direta é: \u003cstrong\u003eIntelliJ IDEA é a melhor IDE para Kotlin de uso geral, e Android Studio é a melhor para desenvolvimento Android\u003c/strong\u003e. Mas existem outras opções válidas dependendo do seu contexto. Vamos analisar cada uma em profundidade.\u003c/p\u003e\n\u003ch3 id=\"intellij-idea-a-referência-para-kotlin\"\u003eIntelliJ IDEA: a referência para Kotlin\u003c/h3\u003e\n\u003cp\u003eIntelliJ IDEA, desenvolvida pela JetBrains (a mesma empresa que criou o Kotlin), é a IDE com o melhor suporte para a linguagem. Isso não é coincidência: o plugin de Kotlin foi desenvolvido em conjunto com a IDE, garantindo integração profunda e funcionalidades exclusivas.\u003c/p\u003e","title":"Qual a Melhor IDE para Programar em Kotlin? | Kotlin Brasil"},{"content":"Login com senha continua sendo uma das partes mais frágeis de muitos apps Android. O usuário esquece senha, reutiliza a mesma credencial em vários serviços, cai em phishing, abandona cadastro quando o fluxo pede etapas demais e ainda espera que a experiência funcione no celular com a mesma naturalidade de um app nativo. Em 2026, passkeys no Android com Kotlin viraram uma alternativa real para reduzir atrito e melhorar segurança sem obrigar todo produto a manter uma pilha complexa de autenticação própria.\nPasskeys combinam criptografia de chave pública, WebAuthn/FIDO2, biometria ou bloqueio de tela do dispositivo e sincronização segura pelo provedor de credenciais. Para o usuário, a experiência parece simples: tocar em \u0026ldquo;entrar\u0026rdquo;, confirmar com impressão digital, rosto ou PIN e seguir. Para a engenharia, o ganho é maior: a aplicação deixa de enviar senha reutilizável e passa a trabalhar com desafios assinados, reduzindo risco de vazamento de senha e ataques de phishing.\nEste guia mostra como pensar a implementação em Android usando Kotlin, Credential Manager, backend Kotlin e boas práticas de produto. A ideia não é transformar este artigo em uma especificação completa de WebAuthn, mas explicar o fluxo que uma equipe precisa dominar antes de colocar passkeys em produção. Se você já leu nosso conteúdo sobre segurança de dados locais no Android e Spring Security com Kotlin, este é um próximo passo natural.\nO que são passkeys? Uma passkey é uma credencial baseada em par de chaves criptográficas. A chave privada fica protegida no dispositivo ou no provedor de credenciais do usuário. A chave pública fica registrada no servidor. Quando o usuário tenta entrar, o servidor gera um desafio, o app pede ao Credential Manager para assinar esse desafio e o backend valida a assinatura usando a chave pública já cadastrada.\nEssa diferença muda bastante a superfície de risco. Em um login com senha, o servidor recebe um segredo que o usuário conhece e provavelmente reutiliza. Em um login com passkey, o servidor recebe uma prova criptográfica daquele momento. Mesmo que alguém intercepte a resposta, ela não vira uma senha reutilizável para outro site.\nNa prática, passkeys ajudam contra:\nreutilização de senhas vazadas; phishing em páginas falsas; ataques de força bruta contra login; atrito de recuperação de senha; credenciais fracas criadas apenas para concluir cadastro rápido. Elas não eliminam toda responsabilidade de segurança. Você ainda precisa proteger sessão, tokens, recuperação de conta, dispositivos perdidos, logs e autorização. Passkey resolve autenticação primária, não toda a arquitetura de identidade.\nOnde entra o Credential Manager? No Android moderno, o caminho recomendado para trabalhar com passkeys é a biblioteca Credential Manager. Ela oferece uma API unificada para recuperar credenciais salvas, criar passkeys, usar senhas existentes quando necessário e integrar provedores de credenciais disponíveis no dispositivo.\nIsso evita que o app implemente manualmente detalhes de UI e descoberta de credenciais. O Android apresenta a experiência apropriada, o usuário escolhe a credencial e o app recebe uma resposta para enviar ao backend.\nEm um fluxo simplificado, o app Android faz quatro coisas:\nsolicita ao backend as opções de criação ou autenticação; chama o Credential Manager com essas opções; recebe a resposta assinada pelo dispositivo/provedor; envia a resposta ao backend para verificação final. O backend continua sendo decisivo. Ele precisa gerar desafios aleatórios, validar origem, validar rpId, armazenar chave pública, contar uso da credencial quando aplicável e emitir a sessão apenas depois da verificação.\nDependências básicas no Android Em um projeto Android com Kotlin, a dependência principal fica no módulo do app. As versões mudam com o tempo, então trate o número abaixo como exemplo e confira a versão atual na documentação AndroidX antes de publicar.\ndependencies { implementation(\u0026#34;androidx.credentials:credentials:1.3.0\u0026#34;) implementation(\u0026#34;androidx.credentials:credentials-play-services-auth:1.3.0\u0026#34;) implementation(\u0026#34;com.google.android.libraries.identity.googleid:googleid:1.1.1\u0026#34;) } O credentials fornece a API central. O artefato de Play Services ajuda na compatibilidade com provedores Google em aparelhos Android. Dependendo do seu produto, você pode também aceitar senha tradicional, login federado ou outras credenciais no mesmo ponto de entrada.\nSe o app já usa Kotlin coroutines, a integração fica mais natural, porque as chamadas modernas podem ser executadas em funções suspend e conectadas ao ViewModel sem bloquear a UI.\nCriando uma passkey O cadastro começa no servidor. O backend deve criar um desafio e retornar opções compatíveis com WebAuthn. Em muitos projetos, você usa uma biblioteca de WebAuthn no backend para montar esse JSON corretamente. O app Android não deve inventar challenge, user.id ou rp.id localmente.\nUm exemplo conceitual no Android fica assim:\nclass PasskeyRepository( private val credentialManager: CredentialManager, private val authApi: AuthApi, ) { suspend fun criarPasskey(context: Context): ResultadoLogin { val optionsJson = authApi.iniciarCadastroPasskey() val request = CreatePublicKeyCredentialRequest( requestJson = optionsJson, ) val response = credentialManager.createCredential( context = context, request = request, ) as CreatePublicKeyCredentialResponse return authApi.finalizarCadastroPasskey( credentialJson = response.registrationResponseJson, ) } } O optionsJson geralmente contém dados como challenge, rp, user, algoritmos aceitos, tipo de autenticador e preferências de verificação do usuário. O registrationResponseJson volta com dados que o backend precisa validar e armazenar.\nO detalhe importante é não tratar a criação da passkey como concluída apenas porque o Android retornou uma resposta. A credencial só deve ser considerada ativa depois que o backend validar a resposta e persistir a chave pública com segurança.\nEntrando com uma passkey existente O login segue uma ideia parecida, mas usa GetCredentialRequest com uma opção de chave pública. O backend primeiro gera um desafio de autenticação. O Android pede ao usuário para escolher ou confirmar a credencial. Depois, a resposta assinada volta para o servidor.\nclass LoginComPasskeyUseCase( private val credentialManager: CredentialManager, private val authApi: AuthApi, ) { suspend fun entrar(context: Context): SessaoUsuario { val optionsJson = authApi.iniciarLoginPasskey() val request = GetCredentialRequest( credentialOptions = listOf( GetPublicKeyCredentialOption( requestJson = optionsJson, ), ), ) val result = credentialManager.getCredential( context = context, request = request, ) val credential = result.credential as PublicKeyCredential return authApi.finalizarLoginPasskey( assertionJson = credential.authenticationResponseJson, ) } } Em produção, trate exceções com cuidado. O usuário pode cancelar o fluxo, não ter credencial disponível, estar em um aparelho sem provedor compatível ou encontrar uma falha temporária. Cancelamento não é necessariamente erro de segurança; muitas vezes é apenas uma decisão do usuário. A UI deve oferecer alternativa clara, como login por e-mail, magic link ou senha, dependendo da estratégia do produto.\nComo o backend Kotlin participa O backend é a parte que mais precisa de disciplina. Em uma API Kotlin com Ktor ou Spring Boot, o fluxo de passkey normalmente tem quatro endpoints:\nPOST /auth/passkeys/registration/options para gerar opções de cadastro; POST /auth/passkeys/registration/verify para validar e salvar a nova credencial; POST /auth/passkeys/authentication/options para gerar desafio de login; POST /auth/passkeys/authentication/verify para validar assinatura e emitir sessão. Um esboço com Ktor poderia ficar assim:\nfun Route.passkeyRoutes(service: PasskeyService) { route(\u0026#34;/auth/passkeys\u0026#34;) { post(\u0026#34;/registration/options\u0026#34;) { val user = call.principal\u0026lt;UsuarioPrincipal\u0026gt;() call.respond(service.criarOpcoesCadastro(user.id)) } post(\u0026#34;/registration/verify\u0026#34;) { val payload = call.receive\u0026lt;PasskeyRegistrationPayload\u0026gt;() val resultado = service.verificarCadastro(payload) call.respond(resultado) } post(\u0026#34;/authentication/options\u0026#34;) { val payload = call.receive\u0026lt;PasskeyLoginStartPayload\u0026gt;() call.respond(service.criarOpcoesLogin(payload.email)) } post(\u0026#34;/authentication/verify\u0026#34;) { val payload = call.receive\u0026lt;PasskeyAssertionPayload\u0026gt;() val sessao = service.verificarLogin(payload) call.respond(sessao) } } } O PasskeyService deve delegar a validação WebAuthn para uma biblioteca confiável, não para código caseiro. WebAuthn tem detalhes de encoding, challenge, origem, contador de assinatura, algoritmos e propriedades do autenticador. Implementar isso manualmente aumenta muito o risco de aceitar uma assinatura inválida.\nSe você usa Spring Boot, a mesma separação vale: controller fino, service com regra de identidade, repositório para credenciais e emissão de sessão isolada. O artigo de Spring Security com JWT e OAuth2 ajuda a pensar a etapa posterior: depois que a passkey autentica o usuário, como a API protege rotas e tokens.\nArmazenamento de credenciais no servidor Cada credencial precisa ser armazenada com metadados suficientes para auditoria e validação. Um modelo simplificado poderia incluir:\ndata class PasskeyCredential( val id: String, val userId: String, val publicKeyCose: ByteArray, val signCount: Long, val transports: List\u0026lt;String\u0026gt;, val createdAt: Instant, val lastUsedAt: Instant?, val label: String?, ) Não salve apenas a chave pública e esqueça o resto. lastUsedAt ajuda suporte e segurança. label permite mostrar ao usuário algo como “Celular pessoal” ou “Notebook do trabalho”. transports pode ajudar diagnóstico. O contador de assinatura, quando usado, ajuda a detectar alguns cenários suspeitos, embora nem todo autenticador moderno se comporte da mesma forma.\nTambém vale permitir múltiplas passkeys por usuário. Uma pessoa pode usar celular, notebook e gerenciador de senhas. Forçar uma única credencial aumenta risco de bloqueio de conta.\nUX: passkey não pode virar beco sem saída O maior erro de produto é vender passkey como se ela eliminasse todos os fluxos alternativos. Dispositivos são perdidos, contas são restauradas, usuários trocam de ecossistema, provedores falham e empresas têm políticas diferentes para aparelhos corporativos.\nUma experiência saudável deve prever:\ncadastro de mais de uma passkey; nome amigável para credenciais cadastradas; remoção de credencial antiga; recuperação de conta com verificação forte; fallback documentado para suporte; comunicação clara quando o usuário cancela o prompt. No Android, também tome cuidado com o momento de pedir a passkey. Se você coloca a criação no primeiro segundo do onboarding, antes de explicar valor, muita gente cancela. Um bom padrão é autenticar ou cadastrar a conta primeiro, mostrar o benefício e oferecer a criação da passkey como melhoria de segurança e conveniência.\nSegurança local e sessão depois do login Passkey autentica o usuário, mas o app ainda precisa guardar estado de sessão. Isso pode envolver access token curto, refresh token, cookies ou outro mecanismo definido pelo backend. A regra continua a mesma: tokens sensíveis não devem ficar em armazenamento local comum sem avaliação de risco.\nPara apps Android, combine passkeys com práticas como:\ntoken de acesso curto; refresh token protegido com armazenamento adequado; limpeza de sessão no logout; logs sem tokens ou respostas WebAuthn completas; cuidado com backup automático de dados sensíveis; reautenticação para ações críticas. Esse ponto conversa diretamente com segurança de dados locais no Android e com apps offline-first com Kotlin. Se o app permite ações offline, pense como elas se comportam quando a sessão expira, quando o usuário remove uma passkey ou quando o dispositivo volta de uma restauração de backup.\nTestes que valem o esforço Testar passkeys exige separar níveis. Você não precisa automatizar toda a biometria real em teste unitário, mas precisa testar regras de backend e estados de UI.\nNo Android, cubra pelo menos:\nusuário cancela criação da passkey; dispositivo sem credencial disponível; backend retorna desafio inválido ou expirado; login bem-sucedido emite sessão; falha de rede durante verificação; UI oferece fallback sem esconder o erro. No backend, os testes mais importantes validam challenge único, expiração, origem esperada, persistência da credencial, emissão de sessão e rejeição de payload reaproveitado. Se o backend usa uma biblioteca WebAuthn, teste a integração ao redor dela e não duplique a suíte interna da biblioteca.\nPara times que já usam JUnit e MockK, o desenho fica mais simples se o Credential Manager estiver atrás de uma interface própria. Assim, ViewModel e use cases podem receber respostas fake sem depender de prompt real do sistema.\ninterface PasskeyClient { suspend fun criar(optionsJson: String): String suspend fun autenticar(optionsJson: String): String } class LoginViewModel( private val passkeyClient: PasskeyClient, private val authApi: AuthApi, ) : ViewModel() { fun loginComPasskey() = viewModelScope.launch { val options = authApi.iniciarLoginPasskey() val assertion = passkeyClient.autenticar(options) authApi.finalizarLoginPasskey(assertion) } } Essa abstração também ajuda a evitar que detalhes de Android vazem para domínio e repository. O código fica mais testável e mais claro para quem mantém a feature depois.\nErros comuns ao implementar passkeys Alguns problemas aparecem com frequência em times que começam rápido demais:\ngerar challenge no app em vez do backend; não validar origin e rpId corretamente; guardar resposta WebAuthn completa em log; tratar cancelamento do usuário como erro fatal; não permitir múltiplas credenciais por conta; criar fallback inseguro que enfraquece todo o ganho da passkey; emitir sessão antes da verificação final do backend; não documentar recuperação de conta. O último ponto é importante. Se a recuperação de conta permite tomar posse com um simples link de e-mail sem proteção adicional, a passkey deixa de ser o elo forte do fluxo. Segurança é sempre o conjunto, não apenas a tecnologia mais moderna da tela de login.\nQuando adotar passkeys em um app Kotlin? Passkeys fazem mais sentido quando o app tem login recorrente, dados sensíveis, risco de phishing, abandono por senha ou base de usuários já acostumada com biometria no celular. Fintechs, saúde, educação, apps corporativos, e-commerce, SaaS mobile e produtos com autenticação frequente tendem a se beneficiar bastante.\nPara um MVP simples, talvez seja melhor começar com login federado ou magic link e planejar passkeys quando a identidade virar gargalo. Para um produto estabelecido, a adoção incremental costuma ser a melhor estratégia: permitir criar passkey depois do login, medir taxa de adesão, acompanhar falhas e só então promover o fluxo como opção principal.\nTambém existe uma oportunidade de carreira. Desenvolvedores Android e backend que entendem passkeys, Credential Manager, WebAuthn e segurança de sessão demonstram maturidade além do CRUD. Em vagas Kotlin, esse conhecimento conversa com Android moderno, arquitetura de autenticação e integração segura com APIs.\nConclusão Passkeys no Android com Kotlin são uma evolução prática, não apenas uma tendência de segurança. Elas reduzem dependência de senhas, melhoram a experiência do usuário e aproximam apps brasileiros de um padrão de autenticação mais resistente a phishing. Mas a implementação correta exige cooperação entre Android, backend, produto e suporte.\nUse Credential Manager para a experiência nativa, deixe o backend gerar e validar desafios, armazene credenciais com metadados, teste cancelamentos e falhas, e mantenha uma estratégia segura de recuperação de conta. Depois do login, continue tratando sessão, tokens e dados locais com a mesma disciplina.\nSe o seu time está modernizando autenticação em Kotlin, passkeys merecem entrar no roadmap ao lado de Spring Security, Ktor para APIs e boas práticas de Android seguro. Para comparar com outro ecossistema backend usado em autenticação e APIs de alta escala, vale acompanhar também conteúdos de Go para serviços web no Golang Brasil.\n","permalink":"https://kotlin.dev.br/blog/passkeys-android-kotlin-credential-manager-2026/","summary":"\u003cp\u003eLogin com senha continua sendo uma das partes mais frágeis de muitos apps Android. O usuário esquece senha, reutiliza a mesma credencial em vários serviços, cai em phishing, abandona cadastro quando o fluxo pede etapas demais e ainda espera que a experiência funcione no celular com a mesma naturalidade de um app nativo. Em 2026, \u003cstrong\u003epasskeys no Android com Kotlin\u003c/strong\u003e viraram uma alternativa real para reduzir atrito e melhorar segurança sem obrigar todo produto a manter uma pilha complexa de autenticação própria.\u003c/p\u003e","title":"Passkeys no Android com Kotlin: Credential Manager em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA CI\u0026T busca uma pessoa Desenvolvedora Backend Java/Kotlin Sênior para atuação remota no Brasil.\nRequisitosExperiência sênior em desenvolvimento Backend com Java e Kotlin.Experiência com Spring Boot.Conhecimento em serviços AWS, incluindo SQS, SNS e Athena.Experiência com PostgreSQL.Modelo de trabalhoVaga remota para profissionais no Brasil.\n","permalink":"https://kotlin.dev.br/vagas/gwye1nh5vq52b8oo-ci-t-desenvolvedor-backend-java-kotlin-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T busca uma pessoa Desenvolvedora Backend Java/Kotlin Sênior para atuação remota no Brasil.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Backend com \u003cstrong\u003eJava\u003c/strong\u003e e \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eSpring Boot\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em serviços AWS, incluindo \u003cstrong\u003eSQS\u003c/strong\u003e, \u003cstrong\u003eSNS\u003c/strong\u003e e \u003cstrong\u003eAthena\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003ePostgreSQL\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais no Brasil.\u003c/p\u003e","title":"Desenvolvedor Backend Java/Kotlin Sênior"},{"content":"Sobre a vagaA Wellhub busca uma pessoa Gerente de Engenharia de Software para atuar na área de Partner Content, em modelo remoto, com contratação aberta para Brasil ou Portugal.\nStack e contexto técnicoA posição envolve trabalho com sistemas backend e APIs, usando tecnologias como Kotlin, Java, Go, Scala, Python, PostgreSQL, MySQL, Redis e APIs RESTful.\nRequisitosExperiência em engenharia de software em nível pleno.Vivência com desenvolvimento backend e integração de APIs RESTful.Experiência com Kotlin, Java, Go ou linguagens similares no ecossistema backend.Conhecimento de bancos relacionais como PostgreSQL e MySQL.Experiência com Redis ou outras soluções de cache.Capacidade de atuar em ambiente remoto e colaborar com times distribuídos.Local de trabalhoVaga remota para profissionais no Brasil ou em Portugal.\n","permalink":"https://kotlin.dev.br/vagas/pev6qhm5qxzaiusu-wellhub-gerente-de-engenharia-de-software-partner-content/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Wellhub busca uma pessoa Gerente de Engenharia de Software para atuar na área de Partner Content, em modelo remoto, com contratação aberta para Brasil ou Portugal.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cp\u003eA posição envolve trabalho com sistemas backend e APIs, usando tecnologias como Kotlin, Java, Go, Scala, Python, PostgreSQL, MySQL, Redis e APIs RESTful.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em engenharia de software em nível pleno.\u003c/li\u003e\u003cli\u003eVivência com desenvolvimento backend e integração de APIs RESTful.\u003c/li\u003e\u003cli\u003eExperiência com Kotlin, Java, Go ou linguagens similares no ecossistema backend.\u003c/li\u003e\u003cli\u003eConhecimento de bancos relacionais como PostgreSQL e MySQL.\u003c/li\u003e\u003cli\u003eExperiência com Redis ou outras soluções de cache.\u003c/li\u003e\u003cli\u003eCapacidade de atuar em ambiente remoto e colaborar com times distribuídos.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais no Brasil ou em Portugal.\u003c/p\u003e","title":"Gerente de Engenharia de Software | Partner Content"},{"content":"Sobre a vagaO C6 Bank busca uma Pessoa Desenvolvedora Backend Java e Kotlin Especialista para atuar em prevenção a fraudes, em modelo presencial em São Paulo.\nResponsabilidadesDesenvolver e evoluir serviços backend para sistemas de prevenção a fraudes.Trabalhar com arquiteturas distribuídas, mensageria e integrações em nuvem.Aplicar boas práticas de engenharia, testes e observabilidade em aplicações críticas.RequisitosExperiência sênior com desenvolvimento backend em Java e Kotlin.Conhecimento em Spring Boot, APIs e serviços distribuídos.Experiência com bancos de dados como PostgreSQL, MongoDB e Cassandra.Vivência com mensageria usando Kafka, SQS ou SNS.Conhecimento em AWS, infraestrutura como código com Terraform ou CloudFormation e pipelines de CI/CD.Familiaridade com autenticação e autorização usando JWT e OAuth2.Experiência com práticas como DDD, TDD/BDD, observabilidade, Docker e tracing distribuído. ","permalink":"https://kotlin.dev.br/vagas/8f6p6ztem2dunsk6-c6-bank-pessoa-desenvolvedora-backend-java-e-kotlin-especialist/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma Pessoa Desenvolvedora Backend Java e Kotlin Especialista para atuar em prevenção a fraudes, em modelo presencial em São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e evoluir serviços backend para sistemas de prevenção a fraudes.\u003c/li\u003e\u003cli\u003eTrabalhar com arquiteturas distribuídas, mensageria e integrações em nuvem.\u003c/li\u003e\u003cli\u003eAplicar boas práticas de engenharia, testes e observabilidade em aplicações críticas.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com desenvolvimento backend em \u003cstrong\u003eJava\u003c/strong\u003e e \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eSpring Boot\u003c/strong\u003e, APIs e serviços distribuídos.\u003c/li\u003e\u003cli\u003eExperiência com bancos de dados como \u003cstrong\u003ePostgreSQL\u003c/strong\u003e, \u003cstrong\u003eMongoDB\u003c/strong\u003e e \u003cstrong\u003eCassandra\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com mensageria usando \u003cstrong\u003eKafka\u003c/strong\u003e, \u003cstrong\u003eSQS\u003c/strong\u003e ou \u003cstrong\u003eSNS\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eAWS\u003c/strong\u003e, infraestrutura como código com \u003cstrong\u003eTerraform\u003c/strong\u003e ou \u003cstrong\u003eCloudFormation\u003c/strong\u003e e pipelines de \u003cstrong\u003eCI/CD\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eFamiliaridade com autenticação e autorização usando \u003cstrong\u003eJWT\u003c/strong\u003e e \u003cstrong\u003eOAuth2\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com práticas como \u003cstrong\u003eDDD\u003c/strong\u003e, \u003cstrong\u003eTDD/BDD\u003c/strong\u003e, observabilidade, \u003cstrong\u003eDocker\u003c/strong\u003e e tracing distribuído.\u003c/li\u003e\u003c/ul\u003e","title":"Pessoa Desenvolvedora Backend Java e Kotlin Especialista"},{"content":"Sobre a vagaVaga presencial para Senior Staff Fullstack com foco em Mobile e Backend no iFood, em Osasco, São Paulo.\nStack mencionadaKotlinAndroid SDKJetpack ComposeFlutter e DartAPIs REST e gRPCSentry e Firebase CrashlyticsPerfilPosição de nível sênior para atuação técnica em produtos mobile e backend. A descrição completa de responsabilidades, requisitos e benefícios não foi informada.\n","permalink":"https://kotlin.dev.br/vagas/6dlyice9wy5fijvw-ifood-senior-staff-fullstack-mobile-backend/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga presencial para Senior Staff Fullstack com foco em Mobile e Backend no iFood, em Osasco, São Paulo.\u003c/p\u003e\u003ch3\u003eStack mencionada\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eAndroid SDK\u003c/li\u003e\u003cli\u003eJetpack Compose\u003c/li\u003e\u003cli\u003eFlutter e Dart\u003c/li\u003e\u003cli\u003eAPIs REST e gRPC\u003c/li\u003e\u003cli\u003eSentry e Firebase Crashlytics\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cp\u003ePosição de nível sênior para atuação técnica em produtos mobile e backend. A descrição completa de responsabilidades, requisitos e benefícios não foi informada.\u003c/p\u003e","title":"Senior Staff Fullstack (Mobile/Backend)"},{"content":"Injeção de dependência parece um assunto abstrato até o primeiro app Android crescer de verdade. No começo, instanciar um Repository dentro do ViewModel funciona. Depois entram API, banco local, analytics, autenticação, feature flags, cache, testes, ambiente de homologação e múltiplos módulos. Sem um grafo claro de dependências, cada tela começa a criar objetos do seu jeito e o projeto fica difícil de testar.\nNo ecossistema Android com Kotlin, Hilt é o caminho oficial mais comum para resolver esse problema. Ele simplifica o Dagger, integra com Application, Activity, Fragment, ViewModel, WorkManager e testes, e valida boa parte do grafo em tempo de compilação. Em 2026, dominar Hilt continua sendo um diferencial forte para vagas Android, principalmente quando combinado com Jetpack Compose, MVVM com Kotlin, Room, Ktor Client resiliente e testes Android com Compose e Maestro.\nEste guia mostra como pensar Hilt em um app real: onde configurar, quando criar módulos, como escolher scopes, como usar qualifiers, como injetar ViewModels e como substituir dependências em testes sem transformar tudo em boilerplate.\nO que Hilt resolve no projeto Android? Hilt cria e entrega objetos para as classes que precisam deles. Em vez de uma tela construir manualmente ApiClient, UsuarioRepository, Database, Logger e Analytics, você declara como cada dependência nasce e deixa o framework montar o grafo. Em apps com muitos módulos Gradle, isso precisa acompanhar uma estratégia clara de modularização Android com Kotlin e Compose, para que features dependam de contratos estáveis em vez de implementações de outras features.\nIsso resolve problemas práticos:\nevita duplicação de configuração em várias telas; centraliza ciclo de vida de objetos caros, como banco e clientes HTTP; facilita trocar implementação real por fake em testes; deixa dependências explícitas no construtor; reduz singletons globais improvisados; antecipa erros de configuração durante o build. A ideia não é “usar framework porque é moderno”. A ideia é manter a arquitetura legível quando o app passa de três telas para trinta.\nConfiguração básica no Gradle Em um projeto Android com Gradle Kotlin DSL, você normalmente adiciona o plugin do Hilt no projeto e no módulo do app. As versões devem acompanhar o Android Gradle Plugin e a documentação atual, mas a estrutura é esta:\nplugins { id(\u0026#34;com.android.application\u0026#34;) id(\u0026#34;org.jetbrains.kotlin.android\u0026#34;) id(\u0026#34;com.google.dagger.hilt.android\u0026#34;) id(\u0026#34;com.google.devtools.ksp\u0026#34;) } dependencies { implementation(\u0026#34;com.google.dagger:hilt-android:2.52\u0026#34;) ksp(\u0026#34;com.google.dagger:hilt-android-compiler:2.52\u0026#34;) implementation(\u0026#34;androidx.hilt:hilt-navigation-compose:1.2.0\u0026#34;) ksp(\u0026#34;androidx.hilt:hilt-compiler:1.2.0\u0026#34;) } Muitos projetos antigos usam kapt. Em bases novas, vale preferir KSP quando a combinação de versões do projeto permite. Se você está organizando versões em libs.versions.toml, veja também o guia de Gradle Version Catalog em Kotlin.\nNo Application, marque a classe com @HiltAndroidApp:\n@HiltAndroidApp class AppKotlinBrasil : Application() Esse ponto inicial permite que Hilt gere os componentes necessários para o app inteiro.\nInjeção por construtor é o padrão preferido Sempre que possível, injete dependências pelo construtor. Isso deixa claro o que a classe precisa para funcionar e facilita testes unitários sem Android.\nclass UsuarioRepository @Inject constructor( private val api: UsuarioApi, private val dao: UsuarioDao, private val logger: AppLogger, ) { suspend fun buscarPerfil(id: String): Usuario { logger.debug(\u0026#34;Buscando perfil $id\u0026#34;) return dao.buscar(id) ?: api.buscarUsuario(id).also { dao.salvar(it) } } } Repare que o repository não sabe como UsuarioApi, UsuarioDao ou AppLogger são criados. Ele apenas declara suas necessidades. Essa separação combina bem com Clean Architecture: casos de uso e repositories dependem de contratos, enquanto detalhes de rede, banco e analytics ficam nas bordas.\nViewModel com Hilt e Compose Para ViewModels, use @HiltViewModel e injete dependências pelo construtor:\n@HiltViewModel class PerfilViewModel @Inject constructor( private val buscarPerfil: BuscarPerfilUseCase, ) : ViewModel() { private val _estado = MutableStateFlow(PerfilState()) val estado: StateFlow\u0026lt;PerfilState\u0026gt; = _estado.asStateFlow() fun carregar(id: String) { viewModelScope.launch { _estado.value = PerfilState(carregando = true) runCatching { buscarPerfil(id) } .onSuccess { _estado.value = PerfilState(usuario = it) } .onFailure { _estado.value = PerfilState(erro = \u0026#34;Não foi possível carregar\u0026#34;) } } } } Em uma tela Compose com Navigation, recupere o ViewModel com hiltViewModel():\n@Composable fun PerfilRoute( viewModel: PerfilViewModel = hiltViewModel(), ) { val estado by viewModel.estado.collectAsStateWithLifecycle() PerfilScreen(estado = estado, onRetry = { viewModel.carregar(\u0026#34;me\u0026#34;) }) } Evite injetar dependências diretamente em Composables. A tela deve receber estado e callbacks. O ViewModel conversa com os casos de uso; os casos de uso conversam com repositories. Essa divisão mantém UI, regra de negócio e infraestrutura separadas.\nQuando criar módulos Hilt A injeção por construtor cobre muita coisa, mas alguns objetos precisam de módulo porque são criados por builder, vêm de biblioteca externa ou dependem de configuração manual. Exemplos: Retrofit, OkHttp, Room, DataStore, Firebase, Apollo, clientes Ktor e implementações de interfaces.\n@Module @InstallIn(SingletonComponent::class) object RedeModule { @Provides @Singleton fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .build() @Provides @Singleton fun provideRetrofit(client: OkHttpClient): Retrofit = Retrofit.Builder() .baseUrl(\u0026#34;https://api.exemplo.com/\u0026#34;) .client(client) .addConverterFactory(MoshiConverterFactory.create()) .build() @Provides fun provideUsuarioApi(retrofit: Retrofit): UsuarioApi = retrofit.create(UsuarioApi::class.java) } Use módulos para construção, não para esconder arquitetura. Se todo objeto do app vira um método @Provides, provavelmente você está perdendo a vantagem da injeção por construtor.\nEntendendo scopes sem exagerar Scopes dizem por quanto tempo uma instância deve viver. O mais conhecido é @Singleton, que cria uma instância por aplicação. Ele faz sentido para banco, cliente HTTP, storage de preferências e serviços compartilhados.\nMas nem tudo precisa ser singleton. Um use case geralmente pode ser sem escopo. Um objeto leve e stateless pode ser recriado sem problema. Scopes demais deixam o grafo rígido e podem segurar referências mais tempo do que deveriam.\nAlguns componentes comuns:\nScope Quando usar Cuidado @Singleton banco, client HTTP, repository com cache global não guardar referência de Activity ou View @ActivityRetainedScoped estado compartilhado entre ViewModels da mesma Activity não confundir com ciclo de tela Compose @ViewModelScoped dependência específica daquele ViewModel não usar para objeto que precisa sobreviver ao app sem scope use cases simples, mappers, formatadores ok para objetos baratos A regra prática: comece sem scope. Adicione scope quando houver motivo claro de ciclo de vida, custo de criação ou compartilhamento de estado.\nInterfaces, implementações e @Binds Quando uma camada depende de interface, use @Binds para dizer qual implementação concreta Hilt deve entregar.\ninterface AuthRepository { suspend fun usuarioAtual(): Usuario? } class AuthRepositoryRemoto @Inject constructor( private val api: AuthApi, private val tokenStore: TokenStore, ) : AuthRepository { override suspend fun usuarioAtual(): Usuario? = api.me(tokenStore.token()) } @Module @InstallIn(SingletonComponent::class) abstract class RepositoryModule { @Binds @Singleton abstract fun bindAuthRepository( impl: AuthRepositoryRemoto, ): AuthRepository } Prefira @Binds para interface-implementação simples. Use @Provides quando precisar executar lógica de criação.\nQualifiers para dependências do mesmo tipo Às vezes existem duas dependências do mesmo tipo: duas URLs base, dois dispatchers, dois clientes HTTP ou duas instâncias de analytics. Hilt não consegue adivinhar qual usar. Para isso, use qualifiers.\n@Qualifier @Retention(AnnotationRetention.BINARY) annotation class ApiBaseUrl @Qualifier @Retention(AnnotationRetention.BINARY) annotation class CdnBaseUrl @Module @InstallIn(SingletonComponent::class) object UrlModule { @Provides @ApiBaseUrl fun provideApiBaseUrl(): String = \u0026#34;https://api.exemplo.com/\u0026#34; @Provides @CdnBaseUrl fun provideCdnBaseUrl(): String = \u0026#34;https://cdn.exemplo.com/\u0026#34; } Na classe consumidora:\nclass ImagemService @Inject constructor( @CdnBaseUrl private val cdnBaseUrl: String, ) Não use @Named(\u0026quot;api\u0026quot;) em tudo por preguiça. Qualifiers próprios são mais refatoráveis, documentam intenção e evitam erro de string.\nTestes com substituição de dependências Um dos maiores ganhos de Hilt é trocar dependências reais por fakes em testes de integração Android. Para testes instrumentados, use @HiltAndroidTest e HiltAndroidRule:\n@HiltAndroidTest class PerfilScreenTest { @get:Rule val hiltRule = HiltAndroidRule(this) @Before fun setup() { hiltRule.inject() } } Para substituir um módulo inteiro em teste, use @TestInstallIn:\n@Module @TestInstallIn( components = [SingletonComponent::class], replaces = [RedeModule::class] ) object FakeRedeModule { @Provides @Singleton fun provideUsuarioApi(): UsuarioApi = FakeUsuarioApi() } Isso permite testar tela, navegação e ViewModel contra dados previsíveis, sem bater na API real. Em testes unitários puros de ViewModel ou use case, você nem precisa subir Hilt: crie a classe manualmente com fakes no construtor. Hilt é ferramenta de composição do app, não obrigação para todo teste.\nHilt, WorkManager e tarefas em background Para workers, Hilt também ajuda bastante. Em apps offline-first, é comum um Worker precisar de repository, logger e sincronizador. Use @HiltWorker e @AssistedInject:\n@HiltWorker class SyncWorker @AssistedInject constructor( @Assisted context: Context, @Assisted params: WorkerParameters, private val syncRepository: SyncRepository, ) : CoroutineWorker(context, params) { override suspend fun doWork(): Result = runCatching { syncRepository.sincronizarPendentes() } .fold( onSuccess = { Result.success() }, onFailure = { Result.retry() }, ) } Combine isso com o guia de WorkManager com Kotlin para não misturar fila offline, regra de negócio e agendamento em uma classe gigante.\nErros comuns com Hilt Os problemas mais frequentes em projetos Android não vêm do Hilt em si, mas de uso apressado:\nInjetar contexto errado: use @ApplicationContext para dependências de app. Evite guardar Activity em singletons. Transformar tudo em singleton: singletons demais criam estado global disfarçado. Colocar regra de negócio em módulos: módulos devem construir objetos, não decidir fluxo de produto. Injetar em Composables diretamente: prefira ViewModel e parâmetros de tela. Usar Service Locator manual junto com Hilt: misturar padrões aumenta confusão. Não testar o grafo: pelo menos uma suíte instrumentada deve garantir que o app sobe com dependências reais. Qualifiers genéricos: @Named(\u0026quot;x\u0026quot;) espalhado vira armadilha em refactors. Se o build falha com erro de binding ausente, leia a mensagem de baixo para cima: Hilt geralmente mostra qual classe pediu a dependência, qual tipo faltou e em qual componente.\nHilt ou Koin? Koin continua sendo uma opção Kotlin-first, leve e muito usada, especialmente em projetos multiplataforma. Hilt costuma ser melhor quando o app é Android nativo, segue recomendações oficiais do Google e quer validação mais forte em tempo de compilação. A comparação detalhada está em Koin vs Dagger/Hilt.\nPara um app Android profissional em 2026, escolher Hilt é uma decisão conservadora e forte. A documentação, exemplos oficiais, integração com Jetpack e reconhecimento em entrevistas pesam bastante. Para KMP com compartilhamento amplo, Koin ou injeção manual por construtor podem ser mais naturais.\nChecklist antes de levar para produção Antes de considerar o setup de Hilt pronto, revise:\n@HiltAndroidApp configurado no Application; dependências principais usando injeção por construtor; módulos apenas para objetos que precisam de construção especial; @Singleton limitado a objetos realmente compartilhados; qualifiers próprios para valores do mesmo tipo; ViewModels com @HiltViewModel e estado exposto por StateFlow; testes com fakes para API, banco ou storage sensível; nenhum singleton guardando referência de Activity, Fragment ou View; CI rodando build que valide geração de código. Hilt não substitui arquitetura. Ele só torna a composição da arquitetura mais segura. O ganho aparece quando cada classe declara claramente o que precisa, quando ciclos de vida são escolhidos com intenção e quando testes conseguem trocar bordas reais por fakes sem gambiarra.\nPara quem quer crescer como dev Android Kotlin, Hilt é um desses assuntos que conectam código, arquitetura e empregabilidade. Ele aparece em projetos reais porque resolve um problema real: manter um app grande testável, modular e previsível. Domine o básico, evite scopes desnecessários, escreva módulos pequenos e use testes para provar que o grafo funciona.\nTambém vale olhar para outros ecossistemas de backend e mobile: em aplicações server-side, frameworks de DI e configuração existem há anos em Java, Spring e .NET; em stacks mais explícitas, como Go para APIs, a composição manual é mais comum. Entender esses contrastes ajuda a usar Hilt pelo motivo certo: reduzir acoplamento sem esconder demais o funcionamento do app.\n","permalink":"https://kotlin.dev.br/blog/hilt-android-kotlin-modulos-scopes-testes-2026/","summary":"\u003cp\u003eInjeção de dependência parece um assunto abstrato até o primeiro app Android crescer de verdade. No começo, instanciar um \u003ccode\u003eRepository\u003c/code\u003e dentro do \u003ccode\u003eViewModel\u003c/code\u003e funciona. Depois entram API, banco local, analytics, autenticação, feature flags, cache, testes, ambiente de homologação e múltiplos módulos. Sem um grafo claro de dependências, cada tela começa a criar objetos do seu jeito e o projeto fica difícil de testar.\u003c/p\u003e\n\u003cp\u003eNo ecossistema Android com Kotlin, \u003cstrong\u003eHilt\u003c/strong\u003e é o caminho oficial mais comum para resolver esse problema. Ele simplifica o Dagger, integra com \u003ccode\u003eApplication\u003c/code\u003e, \u003ccode\u003eActivity\u003c/code\u003e, \u003ccode\u003eFragment\u003c/code\u003e, \u003ccode\u003eViewModel\u003c/code\u003e, WorkManager e testes, e valida boa parte do grafo em tempo de compilação. Em 2026, dominar Hilt continua sendo um diferencial forte para vagas Android, principalmente quando combinado com \u003ca href=\"/guias/guia-jetpack-compose/\"\u003eJetpack Compose\u003c/a\u003e, \u003ca href=\"/tutoriais/kotlin-mvvm-tutorial/\"\u003eMVVM com Kotlin\u003c/a\u003e, \u003ca href=\"/tutoriais/kotlin-room-database-tutorial/\"\u003eRoom\u003c/a\u003e, \u003ca href=\"/blog/ktor-client-resiliente-timeout-retry-circuit-breaker-2026/\"\u003eKtor Client resiliente\u003c/a\u003e e \u003ca href=\"/guias/testes-android-compose-maestro/\"\u003etestes Android com Compose e Maestro\u003c/a\u003e.\u003c/p\u003e","title":"Hilt no Android com Kotlin: Módulos, Scopes e Testes | Kotlin Brasil"},{"content":"Publicar um app Android é só o começo. O desafio real aparece quando milhares de aparelhos, versões do Android, fabricantes, redes móveis, estados de login e fluxos de usuário começam a rodar o mesmo código em produção. Um crash que nunca apareceu no emulador pode afetar apenas Android 13 em um modelo específico. Um ANR pode surgir só quando o usuário abre o app com banco local grande. Uma falha de sincronização pode acontecer apenas depois de alternar entre offline e online várias vezes. Sem uma estratégia de observabilidade mobile, o time descobre tudo isso tarde demais.\nÉ nesse ponto que Firebase Crashlytics com Kotlin vira uma ferramenta prática, não apenas um painel bonito. Crashlytics coleta crashes, ANRs, stack traces, versão do app, modelo do dispositivo, sistema operacional, logs e chaves customizadas. Usado com disciplina, ele ajuda a responder três perguntas essenciais: o que quebrou, quem foi afetado e qual mudança provavelmente causou o problema.\nEste guia mostra como instrumentar Crashlytics em apps Android com Kotlin, como registrar contexto útil sem vazar dados sensíveis, como tratar ANRs, como conectar releases e como transformar relatórios em um processo de estabilidade. Se você ainda está montando a base do app, leia também a trilha de Android offline-first com Kotlin, o guia de testes Android com Compose e Maestro e o artigo sobre segurança de dados locais no Android.\nO que Crashlytics resolve de verdade? Crashlytics não impede bug. Ele encurta o caminho entre falha real e correção confiável. Em vez de depender de relato manual do usuário, print do WhatsApp ou comentário genérico na Play Store, você passa a receber grupos de falha com stack trace, frequência, versões afetadas, dispositivos, breadcrumbs e sinais de regressão.\nNa prática, ele ajuda em cenários como:\ncrash em ViewModel depois de uma resposta inesperada da API; NullPointerException em tela Compose por estado parcialmente carregado; erro de migration do Room em usuários que atualizaram de versões antigas; falha de desserialização em Retrofit ou Ktor Client; ANR causado por I/O, banco local ou JSON pesado na main thread; crash em worker de sincronização executado em background; instabilidade depois de ativar uma feature flag ou rollout gradual. O ponto importante é que Crashlytics não substitui testes. Ele complementa. Testes pegam cenários previstos antes do release. Crashlytics mostra o que escapou em aparelhos reais.\nConfiguração básica com Gradle Kotlin DSL Em um projeto Android moderno, a configuração costuma envolver o plugin do Google Services, o plugin do Crashlytics e as dependências do Firebase BoM. No settings.gradle.kts ou no bloco de plugins raiz, você declara as versões compatíveis com seu projeto:\nplugins { id(\u0026#34;com.android.application\u0026#34;) version \u0026#34;8.7.0\u0026#34; apply false id(\u0026#34;org.jetbrains.kotlin.android\u0026#34;) version \u0026#34;2.0.21\u0026#34; apply false id(\u0026#34;com.google.gms.google-services\u0026#34;) version \u0026#34;4.4.2\u0026#34; apply false id(\u0026#34;com.google.firebase.crashlytics\u0026#34;) version \u0026#34;3.0.2\u0026#34; apply false } No módulo do app:\nplugins { id(\u0026#34;com.android.application\u0026#34;) id(\u0026#34;org.jetbrains.kotlin.android\u0026#34;) id(\u0026#34;com.google.gms.google-services\u0026#34;) id(\u0026#34;com.google.firebase.crashlytics\u0026#34;) } dependencies { implementation(platform(\u0026#34;com.google.firebase:firebase-bom:33.7.0\u0026#34;)) implementation(\u0026#34;com.google.firebase:firebase-crashlytics-ktx\u0026#34;) implementation(\u0026#34;com.google.firebase:firebase-analytics-ktx\u0026#34;) } Use sempre versões atuais e compatíveis com Android Gradle Plugin, Kotlin e o restante do app. Em projetos grandes, vale centralizar versões em libs.versions.toml, como explicado no conteúdo sobre Gradle Version Catalog em Kotlin.\nTambém é necessário adicionar o arquivo google-services.json do projeto Firebase ao módulo correto. Esse arquivo identifica o app, mas não deve ser tratado como segredo de servidor. Mesmo assim, revise o processo de configuração para evitar misturar ambientes de desenvolvimento, homologação e produção.\nAtivando coleta com controle por ambiente Nem todo build precisa enviar crash para o painel de produção. Builds locais e de QA podem poluir métricas se usarem o mesmo app Firebase. Uma abordagem simples é separar projetos Firebase por ambiente ou controlar a coleta conforme BuildConfig.\nclass KotlinBrasilApp : Application() { override fun onCreate() { super.onCreate() FirebaseCrashlytics.getInstance() .setCrashlyticsCollectionEnabled(!BuildConfig.DEBUG) } } Em times maiores, prefira uma regra explícita por flavor:\nandroid { productFlavors { create(\u0026#34;dev\u0026#34;) { buildConfigField(\u0026#34;boolean\u0026#34;, \u0026#34;CRASHLYTICS_ENABLED\u0026#34;, \u0026#34;false\u0026#34;) } create(\u0026#34;prod\u0026#34;) { buildConfigField(\u0026#34;boolean\u0026#34;, \u0026#34;CRASHLYTICS_ENABLED\u0026#34;, \u0026#34;true\u0026#34;) } } } Depois, use BuildConfig.CRASHLYTICS_ENABLED na inicialização. Isso evita que uma build interna com dados artificiais pareça um incidente real.\nLogs úteis sem vazar dados sensíveis Crashlytics permite registrar logs que aparecem junto do relatório de crash. Isso é útil para reconstruir os passos finais antes da falha, mas também perigoso se o time registrar payloads completos, tokens, emails, CPF, endereço ou mensagens privadas.\nPrefira logs de evento e estado resumido:\nprivate val crashlytics = FirebaseCrashlytics.getInstance() fun abrirDetalhePedido(idPedido: String, origem: String) { crashlytics.log(\u0026#34;abrir_detalhe_pedido\u0026#34;) crashlytics.setCustomKey(\u0026#34;origem_tela\u0026#34;, origem) crashlytics.setCustomKey(\u0026#34;pedido_id_hash\u0026#34;, idPedido.sha256Curto()) // Carrega dados da tela... } O exemplo usa um hash curto do identificador, não o ID real. A regra é simples: o log deve ajudar engenharia a investigar sem transformar Crashlytics em uma cópia paralela do banco do usuário.\nRegistre informações como:\ntela ou fluxo atual; versão da feature flag; estado resumido de login, sem token; tipo de rede, sem localização precisa; tamanho da fila offline; versão do schema local; resultado de uma migration; nome lógico da operação, não payload completo. Não registre:\naccess token ou refresh token; senha, CPF, cartão, telefone ou endereço; corpo completo de resposta da API; mensagens privadas; coordenadas de localização sem necessidade real; dados de saúde, financeiros ou corporativos identificáveis. Esse cuidado conversa diretamente com segurança de dados locais no Android. Observabilidade sem privacidade vira risco.\nChaves customizadas que realmente ajudam Custom keys são campos anexados ao relatório de crash. Elas ajudam a segmentar falhas por contexto. O erro comum é criar dezenas de chaves sem padrão, com valores livres e difíceis de buscar.\nBoas chaves para apps Android com Kotlin:\ncrashlytics.setCustomKey(\u0026#34;screen\u0026#34;, \u0026#34;checkout_review\u0026#34;) crashlytics.setCustomKey(\u0026#34;auth_state\u0026#34;, \u0026#34;logged_in\u0026#34;) crashlytics.setCustomKey(\u0026#34;network_type\u0026#34;, \u0026#34;cellular\u0026#34;) crashlytics.setCustomKey(\u0026#34;offline_queue_size\u0026#34;, syncQueue.count()) crashlytics.setCustomKey(\u0026#34;room_schema_version\u0026#34;, 12) crashlytics.setCustomKey(\u0026#34;feature_new_checkout\u0026#34;, true) crashlytics.setCustomKey(\u0026#34;compose_enabled\u0026#34;, true) Escolha nomes estáveis, em inglês ou português, mas não misture sem critério. Evite valores de alta cardinalidade, como ID único de pedido, email ou URL completa. Chave customizada boa serve para agrupar investigação. Se cada usuário gera um valor diferente, a busca perde força.\nErros não fatais: quando registrar exception sem crash Nem todo erro derruba o app. Uma API pode falhar e mostrar retry. Uma fila offline pode adiar sincronização. Uma imagem pode não carregar. Esses casos não devem virar crash artificial, mas alguns merecem registro como erro não fatal quando indicam problema de produto ou regressão.\nsuspend fun sincronizar() { try { repository.sincronizarPendentes() } catch (e: HttpException) { if (e.code() \u0026gt;= 500) { FirebaseCrashlytics.getInstance().recordException(e) } throw e } catch (e: SQLiteException) { FirebaseCrashlytics.getInstance().recordException(e) throw e } } Use esse recurso com moderação. Se você registra toda falha de rede como exception, o painel vira ruído. Bons candidatos para não fatais:\nerro de migration do banco local recuperado automaticamente; falha repetida de sincronização em background; contrato de API inesperado; exceção em integração de pagamento recuperada com fallback; estado impossível detectado por regra de domínio; falha em feature flag crítica. Para chamadas HTTP comuns, prefira métricas agregadas e logs estruturados. Crashlytics deve destacar aquilo que precisa de investigação, não substituir analytics.\nANR: o crash silencioso que prejudica retenção ANR significa Application Not Responding. O Android mostra esse erro quando a main thread fica bloqueada tempo demais. Para o usuário, a sensação é pior do que um crash rápido: o app congela, não responde ao toque e parece pesado.\nEm apps Kotlin, causas comuns de ANR incluem:\nchamada de rede fora de coroutine adequada; leitura pesada de arquivo na main thread; query grande no Room sem dispatcher correto; parsing JSON pesado durante composição da tela; loop caro dentro de composable; inicialização excessiva no Application.onCreate(); bloqueio com runBlocking em código de produção; sincronização de dados grandes durante abertura da tela. Crashlytics ajuda a agrupar ANRs e mostrar stack traces, mas a correção depende de arquitetura. Trabalho pesado deve sair da main thread, telas Compose precisam observar estado já preparado e operações de I/O devem passar por repositories com coroutines bem definidas.\nUm padrão básico:\nclass PerfilRepository( private val dao: PerfilDao, private val api: PerfilApi, private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO, ) { suspend fun atualizarPerfil(): Perfil = withContext(ioDispatcher) { val remoto = api.buscarPerfil() dao.salvar(remoto.toEntity()) remoto.toDomain() } } Isso parece simples, mas previne uma classe inteira de problemas. Se o app já usa Room, Retrofit e WorkManager, defina fronteiras claras: ViewModel coordena estado, repository decide dados, dispatcher protege I/O e worker cuida do trabalho adiado.\nCompose: cuidado com recomposição e estado pesado Jetpack Compose melhora muito a ergonomia de UI, mas também muda a forma de investigar travamentos. Uma tela pode parecer correta em testes simples e ainda sofrer com recomposição excessiva, listas sem key, lambdas criando objetos pesados ou derivação de estado dentro do composable.\nEvite fazer trabalho caro diretamente na UI:\n@Composable fun PedidosScreen(state: PedidosState) { // Evite filtrar e ordenar listas grandes aqui a cada recomposição. val pedidos = state.pedidos .filter { it.status == Status.PENDENTE } .sortedByDescending { it.criadoEm } LazyColumn { items(pedidos) { pedido -\u0026gt; PedidoItem(pedido) } } } Prefira preparar a lista no ViewModel ou usar estado derivado com critério quando o custo justificar:\ndata class PedidosState( val pedidosPendentesOrdenados: List\u0026lt;PedidoUi\u0026gt;, val carregando: Boolean, ) Crashlytics pode apontar o ANR, mas a prevenção vem de modelar estado de UI com responsabilidade. Para aprofundar a base, veja o guia de Jetpack Compose e a trilha de testes Android com Kotlin.\nRelease tracking e regressões Crashlytics ganha muito valor quando cada relatório é ligado a uma versão de app, build number e commit. Sem isso, o time sabe que algo quebrou, mas não sabe quando entrou.\nNo Android, mantenha versionName e versionCode consistentes. Em CI/CD, gere build com metadados claros:\nandroid { defaultConfig { versionCode = 12043 versionName = \u0026#34;2.14.3\u0026#34; } } Se o time usa distribuição gradual, acompanhe crashes por versão antes de ampliar rollout. Uma versão com crash-free users abaixo do padrão deve pausar. O mesmo vale para ANR rate. Não trate “não recebi reclamação” como sucesso; usuários simplesmente desinstalam apps instáveis.\nEsse ciclo combina bem com CI/CD para Kotlin e feature flags. Deploy seguro não é só build verde; é observar a versão depois que ela chega a aparelhos reais.\nWorkManager e falhas em background Muitos crashes de app Android moderno não acontecem com uma tela aberta. Eles aparecem em workers: sync offline, upload de foto, limpeza de cache, refresh de dados, envio de evento ou tarefa periódica.\nAo instrumentar workers, registre contexto antes da operação crítica:\nclass SyncWorker( context: Context, params: WorkerParameters, private val syncRepository: SyncRepository, ) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { val crashlytics = FirebaseCrashlytics.getInstance() crashlytics.setCustomKey(\u0026#34;worker\u0026#34;, \u0026#34;sync\u0026#34;) crashlytics.setCustomKey(\u0026#34;attempt\u0026#34;, runAttemptCount) return try { syncRepository.sincronizar() Result.success() } catch (e: IOException) { Result.retry() } catch (e: Exception) { crashlytics.recordException(e) Result.failure() } } } Não envie exception para toda falha transitória. IOException por rede instável é parte normal de um app offline-first. Registre quando o erro indica bug, contrato inválido, estado impossível ou falha persistente depois de várias tentativas.\nProcesso de triagem: do painel ao pull request Ferramenta nenhuma resolve estabilidade se o time não cria rotina. Uma boa triagem semanal ou por release pode seguir este fluxo:\nfiltrar crashes e ANRs por versão atual; priorizar falhas com crescimento recente, usuários afetados ou fluxo crítico; identificar se o grupo começou depois de um release específico; reproduzir com estado parecido, device semelhante ou dados locais simulados; escrever teste de regressão quando possível; corrigir e marcar o issue como resolvido apenas depois do release; acompanhar se o grupo reabre em versões futuras. O erro comum é tratar Crashlytics como caixa de entrada infinita. Nem todo grupo tem o mesmo impacto. Um crash raro em uma tela experimental pesa menos que ANR recorrente no login, checkout, pagamento, busca ou sincronização inicial.\nIntegração com suporte e produto Crashlytics também ajuda fora da engenharia, desde que você defina uma linguagem comum. Suporte pode informar versão do app, modelo do aparelho e horário aproximado do problema. Produto pode sinalizar fluxo crítico. Engenharia cruza isso com grupos de falha.\nEvite pedir ao usuário dados sensíveis ou logs manuais quando o app pode registrar contexto seguro automaticamente. Por outro lado, não transforme cada relatório em vigilância. O objetivo é estabilidade, não coleta excessiva.\nPara times brasileiros com apps em fintech, varejo, saúde, educação, logística ou delivery, essa maturidade pesa em carreira. Vagas Android frequentemente citam Firebase, Crashlytics, CI/CD, testes, analytics, performance e arquitetura. Saber explicar como você investiga falhas reais é tão importante quanto saber montar uma tela Compose.\nErros comuns com Crashlytics Alguns problemas aparecem repetidamente:\nusar o mesmo projeto Firebase para dev e produção: polui métricas e confunde prioridade; registrar dados sensíveis em logs: transforma observabilidade em risco de privacidade; ignorar ANRs: app congelando também destrói experiência; registrar toda falha de rede como exception: cria ruído e esconde problemas reais; não ligar falha a versão: dificulta achar regressão; depender só do stack trace: sem chaves customizadas, falta contexto; marcar issue como resolvido cedo demais: espere o release chegar ao usuário; não escrever teste depois da correção: o mesmo bug volta em outra forma. Crashlytics é mais efetivo quando entra no processo de engenharia, não quando alguém abre o painel só depois de uma crise.\nChecklist para produção Antes de considerar a observabilidade mobile pronta, revise:\ncoleta habilitada corretamente apenas nos ambientes desejados; versionName e versionCode consistentes por release; logs sem tokens, documentos, emails ou payloads sensíveis; custom keys padronizadas para tela, feature, fluxo e estado relevante; estratégia para não fatais com limite de ruído; triagem regular de crashes e ANRs; alertas para regressões em versão nova; testes de regressão para falhas importantes; documentação curta explicando como suporte deve reportar problemas; revisão de privacidade alinhada ao tipo de dado do app. Se você trabalha com backend Kotlin também, vale conectar essa mentalidade ao conteúdo de observabilidade em Kotlin. No mobile, a diferença é que o ambiente do usuário é muito mais variável; por isso, contexto seguro e versões bem rastreadas fazem tanta diferença.\nConclusão Firebase Crashlytics com Kotlin é uma das formas mais pragmáticas de melhorar estabilidade de apps Android em produção. Ele mostra crashes, ANRs e exceções não fatais em aparelhos reais, com contexto suficiente para transformar falhas dispersas em correções priorizadas. Mas o valor não vem só da dependência no Gradle. Vem de instrumentação cuidadosa, logs seguros, chaves customizadas, versionamento, triagem e conexão com testes.\nUm app Android maduro não é aquele que nunca falha. É aquele que detecta falhas rapidamente, protege dados do usuário, aprende com incidentes e reduz regressões a cada release. Para continuar evoluindo a base, combine Crashlytics com WorkManager, Android offline-first, testes Android e CI/CD para Kotlin. Esse conjunto aproxima seu app do padrão que empresas esperam de Android Kotlin em 2026.\n","permalink":"https://kotlin.dev.br/blog/firebase-crashlytics-anr-android-kotlin-2026/","summary":"\u003cp\u003ePublicar um app Android é só o começo. O desafio real aparece quando milhares de aparelhos, versões do Android, fabricantes, redes móveis, estados de login e fluxos de usuário começam a rodar o mesmo código em produção. Um crash que nunca apareceu no emulador pode afetar apenas Android 13 em um modelo específico. Um ANR pode surgir só quando o usuário abre o app com banco local grande. Uma falha de sincronização pode acontecer apenas depois de alternar entre offline e online várias vezes. Sem uma estratégia de observabilidade mobile, o time descobre tudo isso tarde demais.\u003c/p\u003e","title":"Firebase Crashlytics com Kotlin: ANR, Crashes e Logs no Android | Kotlin Brasil"},{"content":"Deep links parecem detalhe de produto até o primeiro incidente real: uma campanha abre a tela errada, um link de recuperação de conta cai na home, uma notificação perde o contexto, ou uma URL pública aceita parâmetros sem validação. Em apps Android com Kotlin, App Links e deep links conectam marketing, onboarding, notificações, login, checkout, suporte e retenção. Por isso, eles precisam ser tratados como parte da arquitetura do app, não como uma regra improvisada dentro da Activity.\nUm deep link é qualquer link que leva a uma área específica do app. Um App Link é um caso mais confiável: uma URL HTTPS associada ao domínio do produto, verificada pelo Android por meio do arquivo assetlinks.json. Na prática, App Links reduzem a fricção porque o sistema pode abrir o app diretamente sem mostrar seletor, enquanto deep links customizados como meuapp://pedido/123 continuam úteis para integrações internas, ambientes de teste ou fluxos onde HTTPS não é possível.\nEste guia mostra como desenhar App Links e deep links em um app Android moderno com Kotlin, Compose e Navigation. A ideia é cobrir produção: contrato de URLs, manifesto, navegação tipada, validação de parâmetros, testes, analytics e segurança. Se você ainda está montando a base Android, combine este conteúdo com Kotlin para Android, Navigation 3 com Compose, testes Android com Compose e Maestro e Firebase Crashlytics com Kotlin.\nQuando usar App Links Use App Links quando a URL representa uma rota real do seu produto e pode ser compartilhada fora do app. Alguns exemplos comuns:\nabrir um produto, artigo, pedido, conversa ou perfil específico; retomar onboarding depois de confirmação por e-mail; levar uma pessoa de uma notificação para a tela exata do evento; abrir uma promoção sem perder o identificador da campanha; direcionar suporte para uma área já autenticada do app; permitir que o site e o app compartilhem a mesma URL pública. O ganho principal é consistência. Se https://exemplo.com/pedidos/123 funciona no navegador, o app pode tratar essa mesma URL como entrada para a tela de detalhe do pedido. Isso melhora SEO, campanhas, compartilhamento e manutenção, porque o time não precisa inventar contratos paralelos para web, mobile e notificações.\nDesenhe o contrato de URLs antes do código O erro mais comum é começar pelo AndroidManifest.xml e decidir as rotas depois. Faça o contrário. Liste os caminhos que o app realmente aceita, quem os gera e quais parâmetros são obrigatórios.\nUm contrato simples pode ficar assim:\nURL Tela Parâmetros Observação /artigos/{slug} detalhe de artigo slug público /vagas/{id} detalhe de vaga id público /conta/confirmar confirmação token sensível /checkout/{cartId} checkout cartId, utm_source exige login Evite URLs que dependem de estado escondido, como /abrir?id=123\u0026amp;tipo=pedido\u0026amp;acao=detalhe. Esse formato parece flexível, mas vira uma API sem contrato. Prefira caminhos explícitos e versionáveis.\nManifesto Android para App Links No Android, você declara os links aceitos dentro da Activity que recebe a entrada. Para App Links HTTPS, use android:autoVerify=\u0026quot;true\u0026quot;:\n\u0026lt;activity android:name=\u0026#34;.MainActivity\u0026#34; android:exported=\u0026#34;true\u0026#34;\u0026gt; \u0026lt;intent-filter android:autoVerify=\u0026#34;true\u0026#34;\u0026gt; \u0026lt;action android:name=\u0026#34;android.intent.action.VIEW\u0026#34; /\u0026gt; \u0026lt;category android:name=\u0026#34;android.intent.category.DEFAULT\u0026#34; /\u0026gt; \u0026lt;category android:name=\u0026#34;android.intent.category.BROWSABLE\u0026#34; /\u0026gt; \u0026lt;data android:scheme=\u0026#34;https\u0026#34; android:host=\u0026#34;exemplo.com\u0026#34; android:pathPrefix=\u0026#34;/artigos\u0026#34; /\u0026gt; \u0026lt;/intent-filter\u0026gt; \u0026lt;intent-filter android:autoVerify=\u0026#34;true\u0026#34;\u0026gt; \u0026lt;action android:name=\u0026#34;android.intent.action.VIEW\u0026#34; /\u0026gt; \u0026lt;category android:name=\u0026#34;android.intent.category.DEFAULT\u0026#34; /\u0026gt; \u0026lt;category android:name=\u0026#34;android.intent.category.BROWSABLE\u0026#34; /\u0026gt; \u0026lt;data android:scheme=\u0026#34;https\u0026#34; android:host=\u0026#34;exemplo.com\u0026#34; android:pathPrefix=\u0026#34;/vagas\u0026#34; /\u0026gt; \u0026lt;/intent-filter\u0026gt; \u0026lt;/activity\u0026gt; Separe filtros quando os caminhos têm comportamentos diferentes. Isso facilita auditoria, testes e remoção futura de rotas antigas. Também evite declarar um pathPrefix=\u0026quot;/\u0026quot; amplo demais se o app só sabe tratar algumas URLs. Quanto mais aberto o filtro, maior o risco de abrir telas inesperadas.\nArquivo assetlinks.json Para o Android verificar que o domínio pertence ao app, publique um arquivo em:\nhttps://exemplo.com/.well-known/assetlinks.json O conteúdo aponta para o pacote Android e o SHA-256 do certificado usado na assinatura:\n[ { \u0026#34;relation\u0026#34;: [\u0026#34;delegate_permission/common.handle_all_urls\u0026#34;], \u0026#34;target\u0026#34;: { \u0026#34;namespace\u0026#34;: \u0026#34;android_app\u0026#34;, \u0026#34;package_name\u0026#34;: \u0026#34;br.dev.exemplo\u0026#34;, \u0026#34;sha256_cert_fingerprints\u0026#34;: [ \u0026#34;AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99\u0026#34; ] } } ] Em times com vários ambientes, documente quais domínios usam certificado de debug, staging e produção. Um App Link que funciona localmente pode falhar em produção se o SHA-256 publicado não corresponder à chave final da Play Store.\nConvertendo URL em destino de navegação Não deixe parsing de URL espalhado em Composables. Crie uma pequena fronteira que transforma Uri em uma intenção de navegação tipada:\nsealed interface DeepLinkDestination { data class Artigo(val slug: String) : DeepLinkDestination data class Vaga(val id: String) : DeepLinkDestination data class ConfirmarConta(val token: String) : DeepLinkDestination data object Home : DeepLinkDestination } fun parseDeepLink(uri: Uri): DeepLinkDestination { val segments = uri.pathSegments return when { segments.size == 2 \u0026amp;\u0026amp; segments[0] == \u0026#34;artigos\u0026#34; -\u0026gt; { DeepLinkDestination.Artigo(slug = segments[1]) } segments.size == 2 \u0026amp;\u0026amp; segments[0] == \u0026#34;vagas\u0026#34; -\u0026gt; { DeepLinkDestination.Vaga(id = segments[1]) } segments == listOf(\u0026#34;conta\u0026#34;, \u0026#34;confirmar\u0026#34;) -\u0026gt; { val token = uri.getQueryParameter(\u0026#34;token\u0026#34;).orEmpty() DeepLinkDestination.ConfirmarConta(token = token) } else -\u0026gt; DeepLinkDestination.Home } } Essa função é simples de testar na JVM. Ela também força o time a decidir o que acontece com URL inválida. Para conteúdo público, cair na home pode ser aceitável. Para confirmação de conta ou checkout, é melhor mostrar uma tela de erro controlada do que tentar seguir com dados incompletos.\nIntegração com Compose e Navigation Na MainActivity, leia o Intent inicial e também trate novos intents quando a Activity já estiver aberta:\nclass MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val initialUri = intent?.data setContent { AppRoot(initialDeepLink = initialUri) } } override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) setIntent(intent) // Encaminhe intent.data para o estado de navegação do app. } } Em apps pequenos, você pode chamar navController.navigate(...) depois de parsear a URL. Em apps maiores, prefira converter o link em evento de aplicação e deixar a camada de navegação decidir o destino. Isso combina melhor com StateFlow, ViewModel e navegação orientada a estado.\nUm exemplo direto com Navigation Compose tradicional:\nfun NavController.openDeepLink(destination: DeepLinkDestination) { when (destination) { is DeepLinkDestination.Artigo -\u0026gt; navigate(\u0026#34;artigos/${destination.slug}\u0026#34;) is DeepLinkDestination.Vaga -\u0026gt; navigate(\u0026#34;vagas/${destination.id}\u0026#34;) is DeepLinkDestination.ConfirmarConta -\u0026gt; navigate(\u0026#34;conta/confirmar\u0026#34;) DeepLinkDestination.Home -\u0026gt; navigate(\u0026#34;home\u0026#34;) } } Se você estiver usando Navigation 3, a mesma ideia vale, mas o destino pode ser uma chave serializável em vez de uma string. Isso reduz erro de rota e facilita restauração de estado.\nSegurança e validação Deep link é entrada externa. Trate como input não confiável.\nValide host, caminho e parâmetros antes de navegar. Nunca execute ação destrutiva apenas porque uma URL chegou ao app. Uma rota como /conta/excluir?confirm=true seria perigosa se abrisse uma ação irreversível sem tela de confirmação. Também evite colocar dados sensíveis em query string, porque URLs podem aparecer em logs, analytics, screenshots e histórico do navegador.\nPara fluxos autenticados, o link deve levar até uma tela que verifica sessão. Se o usuário não estiver logado, salve o destino pendente de forma segura, faça login e só depois continue. Para tokens de confirmação, use validade curta, uso único e tratamento claro para token expirado.\nAnalytics sem vazar dados Instrumente eventos de deep link para saber se campanhas e notificações funcionam, mas não envie o token nem identificadores sensíveis. Um evento útil pode conter:\nrota normalizada, como /vagas/{id}; origem, como push, e-mail, web ou campanha; resultado, como aberto, inválido, exige login ou expirado; versão do app e plataforma. Evite registrar a URL completa quando ela contém token, email, cpf, session, cartId ou qualquer dado pessoal. Para estabilidade, conecte falhas de parsing e URLs inesperadas ao seu processo de observabilidade, como explicado no guia de Crashlytics com Kotlin.\nTestes que realmente pegam regressão Comece com testes unitários para parseDeepLink. Eles são baratos e pegam a maioria dos erros de contrato:\n@Test fun `abre artigo por slug`() { val uri = \u0026#34;https://exemplo.com/artigos/navigation-3\u0026#34;.toUri() val destination = parseDeepLink(uri) assertEquals( DeepLinkDestination.Artigo(\u0026#34;navigation-3\u0026#34;), destination, ) } Depois, adicione um teste instrumentado ou E2E para uma jornada crítica. Com ADB, é possível disparar uma intent real:\nadb shell am start \\ -a android.intent.action.VIEW \\ -d \u0026#34;https://exemplo.com/vagas/123\u0026#34; \\ br.dev.exemplo Em Maestro, o fluxo pode abrir o link e verificar a tela esperada. Não automatize todas as rotas. Escolha login, recuperação de conta, checkout, detalhe público e uma rota inválida. Essa seleção cobre risco real sem criar uma suíte lenta.\nChecklist de produção Antes de considerar App Links prontos para produção, revise:\ncontrato de URL documentado e aprovado por web, mobile e produto; AndroidManifest.xml sem filtros amplos demais; assetlinks.json publicado no domínio correto com SHA-256 de produção; parsing de URL coberto por testes unitários; rotas sensíveis exigem autenticação e confirmação explícita; analytics usa rota normalizada, não URL completa com dados sensíveis; links de campanha, push e e-mail testados em dispositivo real; comportamento definido para app instalado, app não instalado e usuário deslogado. App Links bem feitos não são apenas conveniência. Eles conectam aquisição, retenção, suporte e arquitetura. Para quem trabalha com Android Kotlin em produto real, dominar esse fluxo demonstra maturidade: você entende navegação, segurança, analytics, testes e experiência do usuário como partes do mesmo sistema.\n","permalink":"https://kotlin.dev.br/blog/app-links-deep-links-android-kotlin-2026/","summary":"\u003cp\u003eDeep links parecem detalhe de produto até o primeiro incidente real: uma campanha abre a tela errada, um link de recuperação de conta cai na home, uma notificação perde o contexto, ou uma URL pública aceita parâmetros sem validação. Em apps Android com Kotlin, \u003cstrong\u003eApp Links e deep links\u003c/strong\u003e conectam marketing, onboarding, notificações, login, checkout, suporte e retenção. Por isso, eles precisam ser tratados como parte da arquitetura do app, não como uma regra improvisada dentro da \u003ccode\u003eActivity\u003c/code\u003e.\u003c/p\u003e","title":"App Links e Deep Links no Android com Kotlin | Kotlin Brasil"},{"content":"Build lento é um imposto diário em times Kotlin. Cada ./gradlew test, cada pipeline de pull request e cada geração de APK ou artefato backend consome minutos que se repetem centenas de vezes por semana. Em projetos pequenos, isso parece só irritante. Em monorepos Kotlin com módulos Android, bibliotecas compartilhadas, Kotlin Multiplatform, Ktor, Spring Boot e ferramentas de qualidade, build lento vira gargalo de produto.\nA boa notícia é que o ecossistema Gradle amadureceu muito. Em 2026, um projeto Kotlin bem configurado pode combinar Gradle build cache, configuration cache, convention plugins, paralelismo e fronteiras modulares claras para reduzir tempo de feedback sem transformar o build em uma caixa-preta frágil. O ganho não vem de uma única flag milagrosa. Ele vem de disciplina: tarefas determinísticas, inputs declarados, outputs cacheáveis e CI desenhado para reaproveitar trabalho com segurança.\nEste guia mostra uma estratégia prática para acelerar builds Kotlin em monorepos. Se você está organizando a base do projeto, leia também o guia de Kotlin com Gradle, o tutorial de Gradle com Kotlin DSL e o artigo sobre CI/CD para Kotlin.\nO que o build cache realmente faz O Gradle build cache reaproveita o resultado de tarefas quando os inputs são equivalentes. Se uma tarefa de compilação, teste, lint ou empacotamento já rodou com os mesmos arquivos, parâmetros e ambiente relevante, o Gradle pode baixar ou reutilizar o output em vez de executar tudo de novo.\nIsso é diferente de simplesmente “não rodar porque nada mudou”. O estado UP-TO-DATE vale dentro do mesmo workspace. O build cache permite reaproveitamento entre workspaces, branches, máquinas de dev e jobs de CI. Em um monorepo, isso é enorme: um pull request que muda apenas um módulo de feature não deveria recompilar tudo que já foi validado em outro job.\nA regra central é determinismo. Uma tarefa cacheável precisa produzir o mesmo output para os mesmos inputs. Se ela lê hora atual, caminho absoluto local, variável de ambiente não declarada ou arquivo fora do conjunto de inputs, o cache fica perigoso. Por isso, acelerar build não é só “ligar cache”; é remover comportamento implícito.\nConfiguração mínima no settings.gradle.kts O ponto de partida costuma ficar em settings.gradle.kts:\nbuildCache { local { isEnabled = true directory = File(rootDir, \u0026#34;.gradle/build-cache\u0026#34;) removeUnusedEntriesAfterDays = 7 } remote\u0026lt;HttpBuildCache\u0026gt; { url = uri(\u0026#34;https://gradle-cache.example.com/cache/\u0026#34;) isEnabled = !System.getenv(\u0026#34;CI\u0026#34;).isNullOrBlank() isPush = System.getenv(\u0026#34;CI\u0026#34;) == \u0026#34;true\u0026#34; \u0026amp;\u0026amp; System.getenv(\u0026#34;GIT_BRANCH\u0026#34;) == \u0026#34;main\u0026#34; } } Em produção, evite copiar esse exemplo sem pensar. O cache remoto deve ter autenticação, isolamento por organização e política clara de push. Um padrão seguro é permitir que branches de pull request leiam do cache, mas só a branch principal publique resultados. Assim você reduz o risco de poluir cache compartilhado com uma branch experimental.\nPara projetos open source ou times pequenos, apenas o cache local já ajuda. Para empresas com CI pesado, o cache remoto costuma pagar o esforço rapidamente.\nConfiguration cache: acelere a fase esquecida Muita gente mede apenas tempo de compilação, mas builds Gradle também gastam tempo configurando projetos, plugins e tarefas. Em monorepos com dezenas ou centenas de módulos, a configuração pode dominar o tempo de comandos pequenos.\nO configuration cache guarda o resultado da fase de configuração para comandos equivalentes. Ative em gradle.properties:\norg.gradle.configuration-cache=true org.gradle.configuration-cache.problems=warn org.gradle.parallel=true org.gradle.caching=true org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8 kotlin.incremental=true No começo, use problems=warn para mapear plugins e scripts incompatíveis. Depois de estabilizar, trate warnings recorrentes como dívida técnica. Scripts que leem ambiente diretamente, chamam processos externos durante configuração ou acessam APIs internas do Gradle costumam quebrar o cache.\nA prática saudável é mover lógica imperativa para tarefas declaradas e convention plugins. O arquivo de build deve declarar o que o módulo é, não executar descoberta complexa toda vez que o Gradle abre.\nConvention plugins deixam o monorepo previsível Monorepo Kotlin sofre quando cada módulo copia blocos de Gradle com pequenas variações. Um módulo Android usa uma versão de JVM target, outro esquece explicitApi, outro configura testes de forma diferente. Além de confundir pessoas, isso atrapalha cache porque tarefas parecidas deixam de ter inputs parecidos.\nConvention plugins resolvem esse problema. Em vez de repetir configuração, você cria plugins internos como kotlin-brasil.android-library, kotlin-brasil.jvm-library ou kotlin-brasil.kmp-library dentro de build-logic.\n// build-logic/src/main/kotlin/KotlinJvmConventionPlugin.kt class KotlinJvmConventionPlugin : Plugin\u0026lt;Project\u0026gt; { override fun apply(target: Project) = with(target) { pluginManager.apply(\u0026#34;org.jetbrains.kotlin.jvm\u0026#34;) extensions.configure\u0026lt;KotlinJvmProjectExtension\u0026gt; { compilerOptions { jvmTarget.set(JvmTarget.JVM_21) allWarningsAsErrors.set(false) } } tasks.withType\u0026lt;Test\u0026gt;().configureEach { useJUnitPlatform() maxParallelForks = Runtime.getRuntime().availableProcessors().coerceAtMost(4) } } } A partir daí, cada módulo fica pequeno:\nplugins { id(\u0026#34;kotlin-brasil.jvm-library\u0026#34;) } dependencies { implementation(project(\u0026#34;:shared:domain\u0026#34;)) testImplementation(libs.junit.jupiter) } Esse padrão conversa bem com Clean Architecture em Kotlin e com a estratégia de modularização Android com Kotlin e Compose porque deixa fronteiras explícitas: domínio, aplicação, infraestrutura, adapters HTTP, apps Android e módulos KMP podem ter convenções próprias sem duplicação.\nModularização que ajuda o cache Cache não salva uma arquitetura com dependências emaranhadas. Se todo módulo depende de :app, qualquer mudança no app invalida muita coisa. Se modelos de domínio ficam misturados com DTOs de API externa, mudanças pequenas atravessam o grafo inteiro.\nUm monorepo Kotlin mais rápido costuma seguir algumas regras:\nmódulos de domínio não dependem de frameworks; módulos de infraestrutura dependem do domínio, não o contrário; features Android dependem de contratos pequenos, não de um módulo gigante comum; código gerado fica isolado para não invalidar módulos que não precisam dele; testes pesados ficam separados de testes unitários rápidos; APIs compartilhadas mudam com cuidado, porque invalidam consumidores. Antes de mexer em cache, rode ./gradlew projects e ./gradlew :module:dependencies nos módulos críticos. O objetivo é entender o grafo. Builds rápidos são consequência de dependências previsíveis.\nCI: leia cache em PR, publique no main Uma configuração de CI comum para monorepos Kotlin é separar validação por camadas. Um job roda checks rápidos, outro roda testes Android, outro gera artefatos, outro faz análise estática. Todos leem cache remoto. Apenas jobs confiáveis no main publicam.\nUm fluxo prático:\npull request abre e restaura cache remoto; CI roda ./gradlew affectedCheck ou uma seleção equivalente de tarefas; jobs de PR nunca fazem push para o cache remoto; merge no main roda validação completa; se passar, publica outputs cacheáveis para acelerar próximos PRs. Se o time ainda não tem detecção de módulos afetados, comece simples com ./gradlew check. Depois evolua para seleção por paths alterados, dependências reversas ou ferramentas como Gradle Enterprise/Develocity quando fizer sentido financeiro. Não transforme a otimização em risco: pular teste errado custa mais que alguns minutos de CI.\nCuidado com segredos e ambiente Um erro perigoso é deixar tarefas cacheáveis dependerem de segredos, tokens ou arquivos locais. Build cache não deve guardar outputs que embutem credenciais, URLs privadas sensíveis ou configurações de produção. Variáveis como API_TOKEN, keystore Android e credenciais de publicação devem ficar em tarefas não cacheáveis ou declaradas com cuidado.\nPara Android, atenção especial a signing configs, google-services.json, flavors e geração de recursos. Para backend, cuidado com arquivos .env, migrações geradas e clientes OpenAPI criados a partir de endpoints instáveis. Sempre pergunte: “se esse output for reutilizado em outra máquina, isso é correto e seguro?”\nTambém vale padronizar versões de JDK, Android Gradle Plugin, Kotlin e Gradle Wrapper. Cache compartilhado entre ambientes diferentes perde eficiência e pode criar bugs difíceis. Use toolchains quando possível:\nkotlin { jvmToolchain(21) } Como medir antes e depois Sem métrica, otimização vira superstição. Antes de mudar tudo, registre tempos para comandos representativos:\n./gradlew clean ./gradlew :app:assembleDebug --scan ./gradlew check --scan ./gradlew test --scan Depois, rode os mesmos comandos em três cenários: workspace limpo, segunda execução local e CI com cache remoto aquecido. O número mais importante para devs costuma ser feedback incremental; o número mais importante para a empresa costuma ser tempo total de PR até merge.\nMesmo sem build scan pago, você pode usar --profile para gerar relatório HTML local:\n./gradlew check --profile Procure tarefas não incrementais, módulos que sempre recompilam, testes lentos e tempo excessivo de configuração. Corrija os maiores gargalos primeiro.\nChecklist de adoção segura Uma implantação gradual reduz risco:\nativar org.gradle.caching=true localmente; corrigir tarefas customizadas que não declaram inputs e outputs; habilitar configuration cache em modo warning; extrair configuração repetida para convention plugins; padronizar JDK via toolchains; isolar tarefas com segredos como não cacheáveis; configurar cache remoto somente leitura em PR; permitir push apenas em CI confiável no main; medir tempo de build antes e depois; documentar como limpar cache quando houver suspeita. Se algo estranho acontecer, desative por escopo em vez de abandonar tudo. Uma tarefa ruim não invalida a estratégia inteira.\nConclusão Gradle build cache em projetos Kotlin não é detalhe de infraestrutura para “quando sobrar tempo”. Ele muda a velocidade de aprendizado do time. Em monorepos com Android, backend e KMP, cada minuto economizado no ciclo de feedback reduz fila de revisão, aumenta confiança para refatorar e libera energia para produto.\nO caminho mais seguro é incremental: entenda o grafo, padronize convenções, ative cache local, estabilize configuration cache, depois leve o cache remoto para CI com política conservadora. Kotlin e Gradle dão ferramentas suficientes para builds rápidos, mas a arquitetura precisa colaborar. Quando módulos têm fronteiras claras e tarefas são determinísticas, o cache deixa de ser aposta e vira multiplicador diário.\nPara continuar, aprofunde em Kotlin com GitHub Actions, Detekt e ktlint em Kotlin e Monólito Modular em Kotlin. Se o seu time também trabalha com Go, o guia de rate limiting em Go ajuda a comparar decisões de CI, performance e confiabilidade entre stacks backend.\n","permalink":"https://kotlin.dev.br/blog/gradle-build-cache-monorepo-kotlin-2026/","summary":"\u003cp\u003eBuild lento é um imposto diário em times Kotlin. Cada \u003ccode\u003e./gradlew test\u003c/code\u003e, cada pipeline de pull request e cada geração de APK ou artefato backend consome minutos que se repetem centenas de vezes por semana. Em projetos pequenos, isso parece só irritante. Em monorepos Kotlin com módulos Android, bibliotecas compartilhadas, Kotlin Multiplatform, Ktor, Spring Boot e ferramentas de qualidade, build lento vira gargalo de produto.\u003c/p\u003e\n\u003cp\u003eA boa notícia é que o ecossistema Gradle amadureceu muito. Em 2026, um projeto Kotlin bem configurado pode combinar \u003cstrong\u003eGradle build cache\u003c/strong\u003e, \u003cstrong\u003econfiguration cache\u003c/strong\u003e, \u003cstrong\u003econvention plugins\u003c/strong\u003e, paralelismo e fronteiras modulares claras para reduzir tempo de feedback sem transformar o build em uma caixa-preta frágil. O ganho não vem de uma única flag milagrosa. Ele vem de disciplina: tarefas determinísticas, inputs declarados, outputs cacheáveis e CI desenhado para reaproveitar trabalho com segurança.\u003c/p\u003e","title":"Gradle Build Cache em Projetos Kotlin: Monorepos Mais Rápidos em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA Applaudo busca uma pessoa para atuar como Arquiteto de Aplicações Android em uma posição remota, com base em Bogotá, Colômbia.\nA vaga envolve arquitetura de soluções Android com Kotlin, integração de APIs, middleware e atenção a segurança mobile e acessibilidade.\nPrincipais temas técnicosArquitetura de aplicações Android com Kotlin.Soluções com MDM, Kiosk Mode e WebView.Orquestração de APIs e integração com middleware.Boas práticas de segurança com OWASP Mobile.Acessibilidade seguindo WCAG 2.1 nível AA.RequisitosExperiência em desenvolvimento ou arquitetura Android.Conhecimento sólido em Kotlin.Familiaridade com segurança em aplicações mobile.Capacidade de desenhar soluções técnicas e orientar decisões de arquitetura. ","permalink":"https://kotlin.dev.br/vagas/deovg4x03uc3pnn5-applaudo-arquiteto-de-aplicacoes-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Applaudo busca uma pessoa para atuar como \u003cstrong\u003eArquiteto de Aplicações Android\u003c/strong\u003e em uma posição remota, com base em Bogotá, Colômbia.\u003c/p\u003e\u003cp\u003eA vaga envolve arquitetura de soluções Android com \u003cstrong\u003eKotlin\u003c/strong\u003e, integração de APIs, middleware e atenção a segurança mobile e acessibilidade.\u003c/p\u003e\u003ch3\u003ePrincipais temas técnicos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eArquitetura de aplicações Android com Kotlin.\u003c/li\u003e\u003cli\u003eSoluções com MDM, Kiosk Mode e WebView.\u003c/li\u003e\u003cli\u003eOrquestração de APIs e integração com middleware.\u003c/li\u003e\u003cli\u003eBoas práticas de segurança com OWASP Mobile.\u003c/li\u003e\u003cli\u003eAcessibilidade seguindo WCAG 2.1 nível AA.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento ou arquitetura Android.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin.\u003c/li\u003e\u003cli\u003eFamiliaridade com segurança em aplicações mobile.\u003c/li\u003e\u003cli\u003eCapacidade de desenhar soluções técnicas e orientar decisões de arquitetura.\u003c/li\u003e\u003c/ul\u003e","title":"Arquiteto de Aplicações Android"},{"content":"Sobre a vagaA Applaudo busca uma pessoa Arquiteta de Aplicações Android para uma posição remota associada a Bogotá, Colômbia. A vaga é de nível pleno e envolve arquitetura de soluções Android com Kotlin.\nTecnologias e temasAndroid e KotlinMDM e Kiosk ModeOrquestração de APIsWebViewOAuth e segurança mobileOWASP MobileAcessibilidade com WCAG 2.1Perfil esperadoExperiência em arquitetura de aplicações Android, com atenção a segurança, integração de APIs, acessibilidade e cenários corporativos envolvendo gerenciamento de dispositivos.\n","permalink":"https://kotlin.dev.br/vagas/g5nph70rvicnejyr-applaudo-arquiteto-de-aplicacoes-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Applaudo busca uma pessoa Arquiteta de Aplicações Android para uma posição remota associada a Bogotá, Colômbia. A vaga é de nível pleno e envolve arquitetura de soluções Android com Kotlin.\u003c/p\u003e\u003ch3\u003eTecnologias e temas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAndroid e Kotlin\u003c/li\u003e\u003cli\u003eMDM e Kiosk Mode\u003c/li\u003e\u003cli\u003eOrquestração de APIs\u003c/li\u003e\u003cli\u003eWebView\u003c/li\u003e\u003cli\u003eOAuth e segurança mobile\u003c/li\u003e\u003cli\u003eOWASP Mobile\u003c/li\u003e\u003cli\u003eAcessibilidade com WCAG 2.1\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil esperado\u003c/h3\u003e\u003cp\u003eExperiência em arquitetura de aplicações Android, com atenção a segurança, integração de APIs, acessibilidade e cenários corporativos envolvendo gerenciamento de dispositivos.\u003c/p\u003e","title":"Arquiteto de Aplicações Android"},{"content":"Sobre a vagaA CI\u0026T busca uma pessoa Desenvolvedora Android Pleno para atuação remota no Brasil, com foco em desenvolvimento mobile.\nRequisitos e tecnologiasExperiência com desenvolvimento Android.Conhecimento em Kotlin e Java.Familiaridade com ferramentas e práticas de engenharia como GitLab, Jenkins, SonarQube e Jira.Conhecimento em AWS é desejável.Informações da vagaEmpresa: CI\u0026T.Senioridade: Pleno.Modelo de trabalho: remoto.Localização: Brasil. ","permalink":"https://kotlin.dev.br/vagas/00zxztt1upbdvf04-ci-t-desenvolvedor-android-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T busca uma pessoa Desenvolvedora Android Pleno para atuação remota no Brasil, com foco em desenvolvimento mobile.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eJava\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eFamiliaridade com ferramentas e práticas de engenharia como GitLab, Jenkins, SonarQube e Jira.\u003c/li\u003e\u003cli\u003eConhecimento em AWS é desejável.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eInformações da vaga\u003c/h3\u003e\u003cul\u003e\u003cli\u003eEmpresa: CI\u0026T.\u003c/li\u003e\u003cli\u003eSenioridade: Pleno.\u003c/li\u003e\u003cli\u003eModelo de trabalho: remoto.\u003c/li\u003e\u003cli\u003eLocalização: Brasil.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android Pleno"},{"content":"Sobre a vagaVaga sênior para Desenvolvimento Android na AB InBev, com atuação presencial em Campinas, São Paulo.\nRequisitos e tecnologiasExperiência com desenvolvimento Android.Conhecimento em Kotlin.Arquiteturas MVVM, MVI e Clean Architecture.Uso de Coroutines e Flow.Experiência com Jetpack Compose.Vivência com práticas de CI/CD. ","permalink":"https://kotlin.dev.br/vagas/nfmthpw8norsuz1x-ab-inbev-desenvolvedor-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga sênior para Desenvolvimento Android na AB InBev, com atuação presencial em Campinas, São Paulo.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin.\u003c/li\u003e\u003cli\u003eArquiteturas MVVM, MVI e Clean Architecture.\u003c/li\u003e\u003cli\u003eUso de Coroutines e Flow.\u003c/li\u003e\u003cli\u003eExperiência com Jetpack Compose.\u003c/li\u003e\u003cli\u003eVivência com práticas de CI/CD.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android Sênior"},{"content":"Sobre a vagaA AB InBev busca uma pessoa Desenvolvedora Android Sênior para atuação presencial em Campinas, São Paulo.\nResponsabilidadesDesenvolver e evoluir aplicações Android usando Kotlin.Aplicar boas práticas de arquitetura, como MVVM, MVI e Clean Architecture.Trabalhar com Coroutines, Flow e Jetpack Compose no desenvolvimento mobile.Contribuir para código sustentável seguindo princípios SOLID.RequisitosExperiência sênior em desenvolvimento Android.Conhecimento sólido em Kotlin.Experiência com MVVM, MVI, Clean Architecture e SOLID.Experiência com Coroutines, Flow e Jetpack Compose.Disponibilidade para atuação presencial em Campinas. ","permalink":"https://kotlin.dev.br/vagas/tt1dntpmw293paqb-ab-inbev-desenvolvedor-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA AB InBev busca uma pessoa Desenvolvedora Android Sênior para atuação presencial em Campinas, São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e evoluir aplicações Android usando Kotlin.\u003c/li\u003e\u003cli\u003eAplicar boas práticas de arquitetura, como MVVM, MVI e Clean Architecture.\u003c/li\u003e\u003cli\u003eTrabalhar com Coroutines, Flow e Jetpack Compose no desenvolvimento mobile.\u003c/li\u003e\u003cli\u003eContribuir para código sustentável seguindo princípios SOLID.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin.\u003c/li\u003e\u003cli\u003eExperiência com MVVM, MVI, Clean Architecture e SOLID.\u003c/li\u003e\u003cli\u003eExperiência com Coroutines, Flow e Jetpack Compose.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação presencial em Campinas.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android Sênior"},{"content":"Sobre a vagaA CI\u0026T busca uma pessoa Desenvolvedora Mobile Sênior/Master para atuação remota na Colômbia, com foco em desenvolvimento mobile.\nRequisitos e tecnologiasExperiência sênior em desenvolvimento mobile.Conhecimento em Kotlin e Android.Experiência com iOS e Objective-C.Vivência com práticas de CI/CD.Uso de ferramentas de monitoramento e analytics como Firebase Crashlytics, Sentry, Datadog, New Relic, AppsFlyer, Google Analytics e Segment.Modelo de trabalhoVaga remota para profissionais na Colômbia.\n","permalink":"https://kotlin.dev.br/vagas/1igzggn0eidsyaa7-ci-t-desenvolvedor-a-mobile-senior-master/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T busca uma pessoa Desenvolvedora Mobile Sênior/Master para atuação remota na Colômbia, com foco em desenvolvimento mobile.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento mobile.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eAndroid\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eiOS\u003c/strong\u003e e \u003cstrong\u003eObjective-C\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com práticas de \u003cstrong\u003eCI/CD\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eUso de ferramentas de monitoramento e analytics como \u003cstrong\u003eFirebase Crashlytics\u003c/strong\u003e, \u003cstrong\u003eSentry\u003c/strong\u003e, \u003cstrong\u003eDatadog\u003c/strong\u003e, \u003cstrong\u003eNew Relic\u003c/strong\u003e, \u003cstrong\u003eAppsFlyer\u003c/strong\u003e, \u003cstrong\u003eGoogle Analytics\u003c/strong\u003e e \u003cstrong\u003eSegment\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais na Colômbia.\u003c/p\u003e","title":"Desenvolvedor(a) Mobile Sênior/Master"},{"content":"Sobre a vagaA Lovevery busca uma pessoa Engenheira Backend Sênior para atuar no Brasil em modelo presencial.\nStack técnicaKotlin/JavaRuby on RailsPythonJavaScriptSwiftAWSRedisRabbitMQElasticsearchDockerRequisitosExperiência sênior em engenharia backend.Vivência com desenvolvimento de serviços, APIs e integrações.Conhecimento em tecnologias de backend e infraestrutura em nuvem. ","permalink":"https://kotlin.dev.br/vagas/spo1eo0c7gph59um-lovevery-engenheiro-backend-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Lovevery busca uma pessoa Engenheira Backend Sênior para atuar no Brasil em modelo presencial.\u003c/p\u003e\u003ch3\u003eStack técnica\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin/Java\u003c/li\u003e\u003cli\u003eRuby on Rails\u003c/li\u003e\u003cli\u003ePython\u003c/li\u003e\u003cli\u003eJavaScript\u003c/li\u003e\u003cli\u003eSwift\u003c/li\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eRedis\u003c/li\u003e\u003cli\u003eRabbitMQ\u003c/li\u003e\u003cli\u003eElasticsearch\u003c/li\u003e\u003cli\u003eDocker\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia backend.\u003c/li\u003e\u003cli\u003eVivência com desenvolvimento de serviços, APIs e integrações.\u003c/li\u003e\u003cli\u003eConhecimento em tecnologias de backend e infraestrutura em nuvem.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro Backend Sênior"},{"content":"Sobre a vagaVaga presencial em São Paulo para Engenheiro(a) de Cyber Security no C6 Bank, com atuação em squads de Atom Security.\nStack e ferramentasLinguagens: Kotlin, Java, Python, Go e Shell.Cloud: AWS, GCP, Azure e OCI.Infraestrutura como código e automação: Terraform, Ansible e CFEngine.Segurança: SIEM.RequisitosExperiência em engenharia de segurança cibernética.Vivência com ambientes cloud e automação de infraestrutura.Conhecimento em desenvolvimento ou scripting para apoiar soluções de segurança.Disponibilidade para atuação presencial em São Paulo. ","permalink":"https://kotlin.dev.br/vagas/stsan6310aue2b7x-c6-bank-engenheiro-a-de-cyber-security-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga presencial em São Paulo para Engenheiro(a) de Cyber Security no C6 Bank, com atuação em squads de Atom Security.\u003c/p\u003e\u003ch3\u003eStack e ferramentas\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eLinguagens:\u003c/strong\u003e Kotlin, Java, Python, Go e Shell.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eCloud:\u003c/strong\u003e AWS, GCP, Azure e OCI.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eInfraestrutura como código e automação:\u003c/strong\u003e Terraform, Ansible e CFEngine.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eSegurança:\u003c/strong\u003e SIEM.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em engenharia de segurança cibernética.\u003c/li\u003e\u003cli\u003eVivência com ambientes cloud e automação de infraestrutura.\u003c/li\u003e\u003cli\u003eConhecimento em desenvolvimento ou scripting para apoiar soluções de segurança.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação presencial em São Paulo.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Cyber Security Sênior"},{"content":"Sobre a vagaO C6 Bank busca uma Pessoa Engenheira de Plataformas Sênior para atuar com Developer Experience em modelo presencial em São Paulo.\nStack e contexto técnicoKotlin, Java, Go e PythonAWS, GCP e OCITerraform e KubernetesRequisitosExperiência sênior em engenharia de plataformas, infraestrutura ou Developer Experience.Vivência com ambientes cloud e ferramentas de infraestrutura como código.Conhecimento em Kubernetes e linguagens como Kotlin, Java, Go ou Python.Local de trabalhoVaga presencial em São Paulo, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/oai4h9a70nk35qnz-c6-bank-pessoa-engenheira-de-plataformas-senior-developer-exper/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma Pessoa Engenheira de Plataformas Sênior para atuar com Developer Experience em modelo presencial em São Paulo.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java, Go e Python\u003c/li\u003e\u003cli\u003eAWS, GCP e OCI\u003c/li\u003e\u003cli\u003eTerraform e Kubernetes\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de plataformas, infraestrutura ou Developer Experience.\u003c/li\u003e\u003cli\u003eVivência com ambientes cloud e ferramentas de infraestrutura como código.\u003c/li\u003e\u003cli\u003eConhecimento em Kubernetes e linguagens como Kotlin, Java, Go ou Python.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em São Paulo, São Paulo, Brasil.\u003c/p\u003e","title":"Pessoa Engenheira de Plataformas Sênior | Developer Experience"},{"content":"SQLDelight é uma das escolhas mais pragmáticas para persistência local em projetos Kotlin Multiplatform. Em vez de tentar esconder o SQLite atrás de um ORM pesado, ele parte de uma ideia simples: você escreve SQL real em arquivos .sq, o plugin valida as queries e gera uma API Kotlin type-safe para Android, iOS, desktop ou outro target suportado.\nPara quem já usa Room com Kotlin no Android, a mudança de mentalidade é importante. Room é excelente quando o app é Android-only e você quer integração direta com Jetpack. SQLDelight brilha quando a camada de dados precisa viver no módulo shared de um projeto Kotlin Multiplatform, principalmente quando Android e iOS devem compartilhar regras de cache, queries, migrations e testes.\nEste guia mostra como pensar SQLDelight em 2026: onde ele entra na arquitetura KMP, como configurar o módulo compartilhado, como escrever queries, como observar dados com Flow e quais cuidados tomar antes de levar para produção.\nQuando SQLDelight faz sentido Use SQLDelight quando o produto precisa de persistência estruturada e a lógica de dados deve ser compartilhada entre plataformas. Exemplos comuns:\napp Android e iOS com cache offline de catálogo, tarefas, pedidos ou mensagens; camada de favoritos, histórico ou fila de sincronização no módulo compartilhado; produto que usa Ktor Client em commonMain e precisa persistir respostas normalizadas; arquitetura offline-first com Kotlin que não deve duplicar regras em Swift e Kotlin Android; app KMP que quer testar repository, migrations e queries sem depender da UI nativa. Se o app é apenas Android, Room continua sendo uma ótima escolha. Se você só precisa salvar tema, onboarding, idioma ou filtros simples, DataStore Preferences é menor e mais direto. SQLDelight entra quando os dados têm tabelas, relacionamentos, busca, ordenação, paginação ou sincronização.\nComo organizar no módulo shared Em um projeto KMP moderno, mantenha SQLDelight dentro do módulo compartilhado. A aplicação Android e o app iOS apenas fornecem o driver específico de plataforma.\nplugins { kotlin(\u0026#34;multiplatform\u0026#34;) id(\u0026#34;com.android.library\u0026#34;) id(\u0026#34;app.cash.sqldelight\u0026#34;) version \u0026#34;2.0.2\u0026#34; } kotlin { androidTarget() iosArm64() iosSimulatorArm64() sourceSets { val commonMain by getting { dependencies { implementation(\u0026#34;app.cash.sqldelight:runtime:2.0.2\u0026#34;) implementation(\u0026#34;app.cash.sqldelight:coroutines-extensions:2.0.2\u0026#34;) } } val androidMain by getting { dependencies { implementation(\u0026#34;app.cash.sqldelight:android-driver:2.0.2\u0026#34;) } } val iosMain by getting { dependencies { implementation(\u0026#34;app.cash.sqldelight:native-driver:2.0.2\u0026#34;) } } } } sqldelight { databases { create(\u0026#34;AppDatabase\u0026#34;) { packageName.set(\u0026#34;br.dev.kotlin.shared.db\u0026#34;) } } } Confira sempre as versões compatíveis com seu Kotlin, Gradle e Android Gradle Plugin. Em times maiores, centralize versões no version catalog para evitar que Android e iOS compilem contra combinações diferentes.\nCriando o schema em arquivos .sq SQLDelight usa arquivos .sq como fonte de verdade. Um arquivo Tarefa.sq pode definir tabela e queries ao mesmo tempo:\nCREATE TABLE tarefa ( id INTEGER NOT NULL PRIMARY KEY, titulo TEXT NOT NULL, concluida INTEGER AS Boolean NOT NULL DEFAULT 0, atualizada_em INTEGER NOT NULL ); listarTodas: SELECT * FROM tarefa ORDER BY atualizada_em DESC; buscarPorId: SELECT * FROM tarefa WHERE id = ?; salvar: INSERT OR REPLACE INTO tarefa(id, titulo, concluida, atualizada_em) VALUES (?, ?, ?, ?); marcarConcluida: UPDATE tarefa SET concluida = ?, atualizada_em = ? WHERE id = ?; O plugin gera código Kotlin para chamar essas queries. Isso reduz uma classe inteira de bugs: nome de coluna errado, tipo incompatível, parâmetro ausente e query quebrada aparecem em build, não só em produção.\nRepository compartilhado com Flow No commonMain, você pode expor dados como Flow e deixar cada plataforma reagir do seu jeito. Android coleta no ViewModel; iOS pode adaptar para Swift usando a estratégia de interop do projeto.\nclass TarefasRepository( private val database: AppDatabase, private val clock: Clock, ) { fun observarTarefas(): Flow\u0026lt;List\u0026lt;Tarefa\u0026gt;\u0026gt; = database.tarefaQueries .listarTodas() .asFlow() .mapToList(Dispatchers.Default) .map { linhas -\u0026gt; linhas.map { it.toDomain() } } fun salvar(tarefa: Tarefa) { database.tarefaQueries.salvar( id = tarefa.id, titulo = tarefa.titulo, concluida = tarefa.concluida, atualizada_em = clock.now().toEpochMilliseconds(), ) } } Repare que o repository não sabe se está rodando no Android ou no iOS. Ele só conhece o banco gerado, modelos de domínio e regras do produto. Essa separação combina com MVVM em Kotlin e com módulos compartilhados focados em lógica, não em detalhes de tela.\nDrivers por plataforma O ponto específico de plataforma é a criação do driver. No Android, você usa AndroidSqliteDriver:\nactual class DatabaseDriverFactory( private val context: Context, ) { actual fun createDriver(): SqlDriver = AndroidSqliteDriver(AppDatabase.Schema, context, \u0026#34;app.db\u0026#34;) } No iOS, use o driver nativo:\nactual class DatabaseDriverFactory { actual fun createDriver(): SqlDriver = NativeSqliteDriver(AppDatabase.Schema, \u0026#34;app.db\u0026#34;) } Esse padrão expect/actual mantém a inicialização separada e permite que o código comum receba apenas AppDatabase(driver).\nMigrations sem improviso SQLDelight valoriza migrations explícitas. Quando o schema evolui, crie arquivos como 1.sqm, 2.sqm e mantenha a sequência versionada no repositório.\nALTER TABLE tarefa ADD COLUMN prioridade INTEGER NOT NULL DEFAULT 0; CREATE INDEX tarefa_prioridade_idx ON tarefa(prioridade); Evite apagar banco em desenvolvimento como solução padrão. Isso esconde problemas que usuários reais terão ao atualizar o app. Teste migration com dados representativos, principalmente quando há filas offline, IDs temporários, relacionamentos ou campos usados por sincronização.\nSQLDelight em arquitetura offline-first Em uma arquitetura offline-first, SQLDelight normalmente guarda três tipos de dados:\nentidades exibidas na UI, como tarefas, produtos, mensagens ou pedidos; metadados de sincronização, como updatedAt, syncStatus e deletedPendingSync; fila de operações pendentes para enviar ao backend quando houver rede. O repository lê primeiro do banco local, grava mudanças localmente e agenda sincronização com uma camada específica de plataforma, como WorkManager no Android. O importante é que a regra de negócio continue no módulo compartilhado. Assim, Android e iOS tomam as mesmas decisões sobre conflito, retry e merge.\nArmadilhas comuns A primeira armadilha é tratar SQLDelight como se fosse Room. Em SQLDelight, SQL é parte central do design. Use isso a favor do projeto: escreva queries claras, índices explícitos e migrations revisáveis.\nA segunda é compartilhar demais. Nem todo detalhe precisa ir para commonMain. Se uma tela iOS usa cache temporário próprio ou se Android depende de API específica do Jetpack, mantenha essa decisão na plataforma. Compartilhe o domínio que realmente precisa ser consistente.\nA terceira é ignorar observabilidade. Bugs de persistência local são difíceis de reproduzir. Registre versão do schema, estado de sincronização e falhas de migration em logs seguros. Para apps críticos, adicione métricas de fila pendente e tempo desde a última sincronização.\nPróximos passos Se você está começando agora, implemente um banco pequeno com duas tabelas, uma migration e um repository compartilhado. Depois conecte esse repository a uma tela Android e a uma tela iOS simples. Esse exercício ensina mais do que copiar uma arquitetura grande pronta.\nPara aprofundar, combine este guia com a comparação Room vs SQLDelight, o guia de Kotlin Multiplatform Mobile, a trilha de Android offline-first e o conteúdo sobre KMP em 2026. Juntos, eles formam uma base sólida para entregar persistência local compartilhada sem sacrificar qualidade nativa.\n","permalink":"https://kotlin.dev.br/blog/sqldelight-kotlin-multiplatform-android-ios-2026/","summary":"\u003cp\u003eSQLDelight é uma das escolhas mais pragmáticas para persistência local em projetos Kotlin Multiplatform. Em vez de tentar esconder o SQLite atrás de um ORM pesado, ele parte de uma ideia simples: você escreve SQL real em arquivos \u003ccode\u003e.sq\u003c/code\u003e, o plugin valida as queries e gera uma API Kotlin type-safe para Android, iOS, desktop ou outro target suportado.\u003c/p\u003e\n\u003cp\u003ePara quem já usa \u003ca href=\"/tutoriais/kotlin-room-database-tutorial/\"\u003eRoom com Kotlin\u003c/a\u003e no Android, a mudança de mentalidade é importante. Room é excelente quando o app é Android-only e você quer integração direta com Jetpack. SQLDelight brilha quando a camada de dados precisa viver no módulo \u003ccode\u003eshared\u003c/code\u003e de um projeto \u003ca href=\"/tutoriais/kotlin-multiplatform-tutorial/\"\u003eKotlin Multiplatform\u003c/a\u003e, principalmente quando Android e iOS devem compartilhar regras de cache, queries, migrations e testes.\u003c/p\u003e","title":"SQLDelight com Kotlin Multiplatform: Android, iOS e SQLite em 2026 | Kotlin Brasil"},{"content":"Feature flags deixaram de ser luxo de empresas grandes. Em 2026, qualquer time que publica aplicativo Android, API backend ou produto SaaS com Kotlin precisa separar deploy de lançamento. Deploy é colocar código novo em produção. Lançamento é liberar comportamento novo para usuários reais. Quando essas duas coisas acontecem sempre juntas, cada mudança vira aposta: se algo quebra, o rollback precisa desfazer todo o deploy, mesmo que o problema esteja em apenas uma tela, endpoint ou regra de negócio.\nCom feature flags, o time consegue publicar código inativo, liberar para um grupo pequeno, medir erro e conversão, desligar rapidamente uma funcionalidade problemática e fazer rollout progressivo sem criar branch eterno. Para quem trabalha com Android offline-first, WorkManager, Kotlin para backend ou CI/CD em Kotlin, esse padrão é especialmente útil porque reduz o risco operacional sem travar a cadência de entrega.\nO ponto importante: feature flag não é apenas um if perdido no código. Ela precisa de nome claro, dono, tipo, data de remoção, valor padrão seguro, testes e observabilidade. Caso contrário, o projeto troca risco de deploy por dívida técnica invisível.\nO que é uma feature flag? Uma feature flag é uma decisão configurável que altera o comportamento do software sem exigir novo build ou novo deploy. Em vez de publicar uma versão diferente para cada público, o mesmo código consulta uma configuração e decide qual caminho executar.\nUm exemplo mínimo em Kotlin:\ninterface FeatureFlags { fun novaTelaCheckout(): Boolean fun usarGatewayPixV2(): Boolean } class CheckoutService( private val flags: FeatureFlags, private val checkoutLegado: CheckoutLegado, private val checkoutNovo: CheckoutNovo, ) { suspend fun finalizarPedido(pedido: Pedido): ResultadoCheckout { return if (flags.novaTelaCheckout()) { checkoutNovo.finalizar(pedido) } else { checkoutLegado.finalizar(pedido) } } } Esse exemplo parece simples, mas já mostra a regra principal: a flag fica atrás de uma interface, não espalhada em chamadas diretas para Firebase Remote Config, LaunchDarkly, Unleash, banco de dados ou arquivo YAML. Essa camada evita acoplamento e facilita testes.\nTipos de feature flags Nem toda flag tem a mesma finalidade. Misturar todos os casos no mesmo padrão costuma gerar confusão.\nRelease flag controla uma funcionalidade nova durante rollout. Deve ser temporária. Exemplo: liberar uma tela de checkout redesenhada para 10% dos usuários.\nOps flag permite desligar comportamento em produção sem rollback. Exemplo: desativar geração de relatório pesado quando um fornecedor externo está instável.\nExperiment flag divide usuários em variantes para teste A/B. Exemplo: comparar dois textos de onboarding medindo ativação.\nPermission flag libera recurso por plano, perfil ou autorização. Exemplo: habilitar exportação CSV apenas para contas Pro.\nMigration flag ajuda a mover tráfego de uma implementação para outra. Exemplo: trocar gradualmente um endpoint Java legado por um serviço Kotlin com Ktor ou Spring Boot.\nA diferença importa porque cada tipo tem ciclo de vida diferente. Release flags devem morrer rápido. Ops flags podem ficar mais tempo, mas precisam ser bem documentadas. Experiment flags precisam de métrica e amostragem consistente. Permission flags quase sempre viram regra de produto permanente.\nFeature flags no Android com Kotlin No Android, feature flags aparecem em três lugares: configuração remota, cache local e UI. O app precisa funcionar mesmo sem rede, então o valor da flag não pode depender de uma chamada síncrona no momento em que a tela abre. Uma estratégia comum é baixar configurações em background, salvar o último valor conhecido e usar um padrão seguro quando nada foi carregado ainda.\nPara flags simples, DataStore Preferences funciona bem como cache local:\nclass AndroidFeatureFlags( private val dataStore: DataStore\u0026lt;Preferences\u0026gt;, ) : FeatureFlags { private val NOVO_CHECKOUT = booleanPreferencesKey(\u0026#34;novo_checkout\u0026#34;) private val PIX_V2 = booleanPreferencesKey(\u0026#34;pix_v2\u0026#34;) suspend fun atualizar(remote: RemoteFlags) { dataStore.edit { prefs -\u0026gt; prefs[NOVO_CHECKOUT] = remote.novoCheckout prefs[PIX_V2] = remote.pixV2 } } override fun novaTelaCheckout(): Boolean { error(\u0026#34;Prefira expor Flow\u0026lt;Boolean\u0026gt; ou snapshot carregado no repository\u0026#34;) } fun novaTelaCheckoutFlow(): Flow\u0026lt;Boolean\u0026gt; = dataStore.data.map { prefs -\u0026gt; prefs[NOVO_CHECKOUT] ?: false } } Em apps reais, evite bloquear a UI esperando configuração remota. Carregue flags durante inicialização, sincronize com WorkManager quando fizer sentido e trate o valor padrão como decisão de produto. Para uma tela crítica, o padrão deve ser conservador. Se a nova experiência falhar, o usuário deve cair no fluxo estável.\nEm Jetpack Compose, conecte a flag como estado vindo do ViewModel:\n@Composable fun CheckoutRoute(viewModel: CheckoutViewModel) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() if (uiState.novoCheckoutAtivo) { NovoCheckoutScreen(uiState) } else { CheckoutLegadoScreen(uiState) } } O cuidado aqui é não transformar a árvore Compose em um labirinto de if. Quando a diferença é grande, prefira separar telas ou componentes inteiros. Quando a diferença é pequena, talvez a flag pertença a um parâmetro de configuração, não à composição inteira.\nFeature flags no backend Kotlin No backend, as flags normalmente entram em controllers, services, consumers de fila e jobs. A regra é parecida: use uma interface própria e mantenha o provedor externo isolado.\nEm Spring Boot com Kotlin:\n@ConfigurationProperties(prefix = \u0026#34;features\u0026#34;) data class FeatureProperties( val antifraudeV2: Boolean = false, val relatorioAssincrono: Boolean = false, ) @Component class BackendFeatureFlags( private val properties: FeatureProperties, ) { fun antifraudeV2(): Boolean = properties.antifraudeV2 fun relatorioAssincrono(): Boolean = properties.relatorioAssincrono } @Service class PagamentoService( private val flags: BackendFeatureFlags, private val antifraudeV1: AntifraudeV1, private val antifraudeV2: AntifraudeV2, ) { suspend fun autorizar(pagamento: Pagamento): DecisaoAntifraude { return if (flags.antifraudeV2()) { antifraudeV2.avaliar(pagamento) } else { antifraudeV1.avaliar(pagamento) } } } Esse modelo com properties resolve casos simples. Para rollout por usuário, empresa, região ou percentual, você provavelmente usará uma plataforma específica ou uma tabela de configuração. Mesmo assim, mantenha a interface do domínio estável. O código de pagamento não precisa saber de onde vem a decisão.\nEm Ktor, a mesma ideia pode ser injetada no módulo da aplicação:\nfun Application.module() { val flags = EnvironmentFeatureFlags(environment.config) routing { post(\u0026#34;/pagamentos\u0026#34;) { val request = call.receive\u0026lt;PagamentoRequest\u0026gt;() val resposta = if (flags.antifraudeV2()) { processarComNovoMotor(request) } else { processarComMotorAtual(request) } call.respond(resposta) } } } Para endpoints críticos, registre logs e métricas com o nome da flag e a variante escolhida. Isso ajuda a responder perguntas práticas: a variante nova aumentou latência? A taxa de erro subiu em uma região? O comportamento falhou apenas para usuários de um plano específico?\nRollout gradual sem perder controle Um rollout seguro começa pequeno. Um fluxo comum:\nPublicar o código com a flag desligada. Ativar para ambiente interno ou equipe de QA. Liberar para 1% dos usuários elegíveis. Medir erro, latência, crash rate, conversão e chamados de suporte. Aumentar para 5%, 25%, 50% e 100% se os indicadores estiverem saudáveis. Remover o caminho antigo quando a nova implementação estiver consolidada. A etapa 6 é a mais esquecida. Flag temporária que nunca morre vira complexidade permanente. Depois de alguns meses, ninguém sabe se pode remover o fluxo antigo, testes precisam cobrir combinações demais e cada refatoração fica mais arriscada.\nUma prática útil é registrar metadados da flag no próprio código ou em um catálogo:\ndata class FeatureFlagMetadata( val key: String, val owner: String, val type: FlagType, val createdAt: LocalDate, val removeAfter: LocalDate?, ) enum class FlagType { RELEASE, OPS, EXPERIMENT, PERMISSION, MIGRATION, } Esse catálogo não precisa ser sofisticado no começo. O importante é responder três perguntas: quem é responsável pela flag, por que ela existe e quando deve ser removida.\nTestando código com feature flags Feature flags aumentam o número de caminhos possíveis. Portanto, teste explicitamente o comportamento ligado e desligado.\nclass FakeFeatureFlags( private val novoCheckout: Boolean, ) : FeatureFlags { override fun novaTelaCheckout(): Boolean = novoCheckout override fun usarGatewayPixV2(): Boolean = false } class CheckoutServiceTest { @Test fun `usa checkout novo quando flag esta ligada`() = runTest { val service = criarService(flags = FakeFeatureFlags(novoCheckout = true)) val resultado = service.finalizarPedido(pedidoValido()) assertEquals(\u0026#34;novo\u0026#34;, resultado.origem) } @Test fun `mantem checkout legado quando flag esta desligada`() = runTest { val service = criarService(flags = FakeFeatureFlags(novoCheckout = false)) val resultado = service.finalizarPedido(pedidoValido()) assertEquals(\u0026#34;legado\u0026#34;, resultado.origem) } } Nem toda combinação precisa de teste end-to-end. O segredo é testar decisões perto da camada onde elas acontecem. Services testam regra de negócio. ViewModels testam estado de UI. Controllers testam contrato HTTP. Testes de interface devem focar nos fluxos mais importantes, não em todas as permutações possíveis.\nTambém vale automatizar uma verificação de flags vencidas. Um teste simples pode falhar quando removeAfter passou da data atual. Isso força o time a tomar decisão: remover, renovar justificativa ou transformar em permissão permanente.\nBoas práticas para 2026 Use nomes explícitos. novoCheckout é melhor que flag1, mas checkoutPixComAntifraudeV2 pode ser ainda mais claro se a mudança for específica. Evite nomes que só fazem sentido para quem participou da reunião original.\nDefina valor padrão seguro. Em Android, o app pode abrir sem configuração remota. Em backend, o provedor de flags pode estar indisponível. O sistema precisa saber qual comportamento usar nesses casos.\nNão coloque lógica de negócio dentro da plataforma de flags. A plataforma decide variante. A regra do domínio continua no código Kotlin, com testes, revisão e versionamento.\nMonitore por variante. Se todos os logs, métricas e traces ignoram a flag, você não consegue saber se o rollout novo está saudável. Combine essa disciplina com observabilidade em Kotlin e, em sistemas distribuídos, com tracing via OpenTelemetry.\nRemova flags antigas. Esse é o ponto que separa maturidade de improviso. Feature flag boa é aquela que permite lançar com segurança e depois desaparece quando não é mais necessária.\nErros comuns O primeiro erro é usar feature flag para esconder código inacabado sem prazo. Isso cria uma falsa sensação de segurança. Código inativo ainda compila, envelhece, interage com dependências e pode confundir futuras refatorações.\nO segundo é consultar a flag em lugares demais. Se a mesma decisão aparece em controller, repository, ViewModel, componente Compose e worker, o comportamento pode ficar inconsistente. Centralize a decisão em uma camada clara.\nO terceiro é não pensar em dados. Uma flag que muda o formato salvo em banco, o schema de uma mensagem Kafka ou a estrutura de cache precisa de estratégia de migração. Desligar a flag talvez não desfaça dados já gravados.\nO quarto é confundir experimento com permissão. Teste A/B mede hipótese temporária. Permissão controla acesso de produto. Misturar os dois dificulta análise e cobrança.\nConclusão Feature flags são uma das práticas mais úteis para times Kotlin que querem entregar rápido sem transformar produção em roleta. Elas ajudam no Android, no backend, em migrações, em experimentos e em operações críticas. Mas o ganho só aparece quando a implementação vem com disciplina: interface própria, valor padrão seguro, rollout gradual, testes para ligado e desligado, observabilidade por variante e limpeza de flags antigas.\nPara começar pequeno, escolha uma funcionalidade nova de risco moderado, coloque atrás de uma release flag, publique desligada, ative para um público interno e acompanhe métricas por alguns dias. Depois avance o rollout e remova o caminho antigo. Esse ciclo simples já muda a cultura do time: deploy deixa de ser evento tenso e vira uma etapa controlada de entrega contínua.\nSe você está montando uma stack Kotlin mais madura, combine feature flags com CI/CD, testes automatizados, observabilidade e arquitetura modular. Para comparar práticas de rollout em outras stacks, também vale estudar como comunidades de Go e Python tratam deploy progressivo, automação e operação de serviços em produção.\n","permalink":"https://kotlin.dev.br/blog/feature-flags-kotlin-android-backend-2026/","summary":"\u003cp\u003eFeature flags deixaram de ser luxo de empresas grandes. Em 2026, qualquer time que publica aplicativo Android, API backend ou produto SaaS com Kotlin precisa separar \u003cstrong\u003edeploy\u003c/strong\u003e de \u003cstrong\u003elançamento\u003c/strong\u003e. Deploy é colocar código novo em produção. Lançamento é liberar comportamento novo para usuários reais. Quando essas duas coisas acontecem sempre juntas, cada mudança vira aposta: se algo quebra, o rollback precisa desfazer todo o deploy, mesmo que o problema esteja em apenas uma tela, endpoint ou regra de negócio.\u003c/p\u003e","title":"Feature Flags em Kotlin: Android, Backend e Rollout Seguro em 2026 | Kotlin Brasil"},{"content":"Segurança de dados locais no Android costuma aparecer tarde demais no projeto. O app começa guardando um token, depois adiciona cache de perfil, preferências, fila offline, histórico de pedidos, dados financeiros ou informações de saúde. Quando o produto cresce, a pergunta muda: o que acontece se esse dispositivo for perdido, roubado, rooteado, restaurado de backup ou analisado por alguém com acesso físico? Em apps Android feitos com Kotlin, proteger armazenamento local precisa fazer parte da arquitetura, não apenas de uma checklist antes de publicar na Play Store.\nO ponto principal é simples: armazenamento local melhora experiência e performance, mas também aumenta responsabilidade. Um app offline-first com Kotlin pode depender de Room, DataStore, WorkManager e cache HTTP para funcionar em rede ruim. Isso é ótimo para produto. Porém, nem todo dado merece ficar salvo em texto claro. Tokens de autenticação, dados pessoais, documentos, mensagens, coordenadas, informações financeiras e registros corporativos precisam de uma estratégia explícita.\nEste guia mostra como pensar segurança local em 2026 usando Kotlin, Android Jetpack, Room, SQLCipher, EncryptedSharedPreferences, Keystore, backups, logs e sincronização. A ideia não é vender “criptografe tudo” como solução mágica. A ideia é separar riscos, escolher ferramentas adequadas e evitar erros que aparecem em entrevistas, auditorias e incidentes reais.\nO que conta como dado local sensível? Antes de escolher biblioteca, classifique os dados. Em muitos projetos, “sensível” vira sinônimo de senha, mas o problema é mais amplo. Em um app Android, dados locais podem incluir:\naccess token, refresh token e chaves de sessão; email, CPF, telefone, endereço e identificadores internos; dados de pagamento, assinatura, pedidos ou saldo; mensagens, anexos e fotos capturadas pelo usuário; localização, rotas, visitas e histórico de uso; cache de APIs com informações de terceiros; filas offline com operações ainda não sincronizadas; flags de feature, permissões e contexto de autorização. Nem todos têm o mesmo risco. Um tema escuro salvo localmente não exige criptografia. Um refresh token sim. Um catálogo público pode ficar em Room sem proteção especial. Uma fila offline com dados de cliente talvez precise ser criptografada, expirar e sair do dispositivo no logout.\nEssa classificação deve acontecer perto da modelagem. Se o time só pergunta “onde vamos guardar?” depois de já ter entidades, repositories e workers prontos, a segurança vira remendo.\nCamadas de armazenamento no Android Apps Kotlin costumam misturar várias camadas locais:\nRoom para dados relacionais, listas, entidades e cache reativo; DataStore Preferences para preferências simples e tipadas; SharedPreferences legadas ou integrações antigas; arquivos internos para anexos, imagens ou documentos; cache HTTP via OkHttp; banco próprio com SQLDelight em projetos multiplataforma; Keystore para proteger chaves criptográficas. Cada camada pede uma decisão diferente. Room é excelente para consulta e reatividade, mas o SQLite padrão não criptografa o arquivo. DataStore melhora ergonomia sobre preferências, mas não deve virar cofre de secrets por padrão. Keystore protege chaves, não substitui banco local. Cache HTTP pode salvar respostas completas sem você perceber se a configuração for permissiva demais.\nPara um app sério, documente a regra por categoria: “tokens ficam no armazenamento criptografado”, “dados públicos podem ficar no Room normal”, “dados pessoais offline expiram em X dias”, “anexos sensíveis não entram no backup”, “logout limpa banco, cache e fila”. Essa clareza evita decisões inconsistentes por tela.\nTokens: onde guardar access token e refresh token? Tokens merecem cuidado especial porque funcionam como credenciais temporárias. A regra prática é: minimize duração, escopo e exposição.\nPara muitos apps Android, EncryptedSharedPreferences ou uma solução equivalente baseada em Android Keystore é um caminho pragmático para tokens. O Keystore protege a chave mestra; as preferências armazenam valores cifrados. Em Kotlin, a inicialização fica parecida com isto:\nval masterKey = MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() val securePrefs = EncryptedSharedPreferences.create( context, \u0026#34;auth_secure_prefs\u0026#34;, masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM, ) securePrefs.edit() .putString(\u0026#34;refresh_token\u0026#34;, refreshToken) .apply() O exemplo mostra o conceito, mas a arquitetura não deve espalhar securePrefs pelo app inteiro. Crie uma fronteira clara:\ninterface TokenStore { suspend fun salvar(tokens: AuthTokens) suspend fun carregar(): AuthTokens? suspend fun limpar() } class AndroidTokenStore( private val prefs: SharedPreferences, ) : TokenStore { override suspend fun salvar(tokens: AuthTokens) { prefs.edit() .putString(\u0026#34;access_token\u0026#34;, tokens.accessToken) .putString(\u0026#34;refresh_token\u0026#34;, tokens.refreshToken) .apply() } override suspend fun carregar(): AuthTokens? { val access = prefs.getString(\u0026#34;access_token\u0026#34;, null) ?: return null val refresh = prefs.getString(\u0026#34;refresh_token\u0026#34;, null) ?: return null return AuthTokens(access, refresh) } override suspend fun limpar() { prefs.edit().clear().apply() } } Essa interface facilita teste, troca de implementação e integração com login biométrico quando necessário. Também evita que interceptors, ViewModels e repositories acessem detalhes de criptografia diretamente.\nAccess token em memória, refresh token persistido Quando possível, reduza persistência. Uma estratégia comum é manter access token curto em memória e persistir apenas refresh token protegido. Ao abrir o app, você usa o refresh token para obter uma sessão nova. Isso reduz o tempo em que um access token válido fica salvo em disco.\nNem sempre essa abordagem cabe no produto. Alguns apps precisam sobreviver a processo morto sem reautenticar toda hora. Mesmo assim, vale perguntar:\no access token precisa mesmo ficar salvo? qual é a expiração real? o refresh token tem rotação? logout invalida token no servidor? troca de senha derruba sessões antigas? o app trata 401 sem loop infinito? Segurança local não compensa backend frágil. Token armazenado com cuidado ainda é perigoso se nunca expira ou se o servidor aceita refresh token antigo depois de rotação.\nRoom e SQLite: quando criptografar o banco? Room usa SQLite. Por padrão, o arquivo do banco fica no sandbox do app, protegido pelo modelo de permissões do Android. Isso já bloqueia acesso casual entre apps. Mas não é criptografia. Em cenários com dados pessoais fortes, dispositivo comprometido, uso corporativo ou requisitos regulatórios, pode fazer sentido usar SQLCipher ou outra camada de banco criptografado.\nCom SQLCipher, a ideia é abrir o banco com uma chave. Em projetos Android, essa chave costuma ser derivada ou protegida por Keystore, não escrita fixa no código. Um desenho simplificado:\nval passphrase: ByteArray = obterChaveDoKeystore() val factory = SupportFactory(passphrase) val db = Room.databaseBuilder( context, AppDatabase::class.java, \u0026#34;app.db\u0026#34;, ) .openHelperFactory(factory) .build() O detalhe importante é operacional: criptografar banco muda backup, migração, performance, recuperação e suporte. Você precisa testar abertura do banco depois de atualização, rotação de chave, logout, reinstalação e restauração de backup. Também precisa evitar logar a chave, salvar passphrase em arquivo ou usar constante hardcoded.\nCriptografar tudo sem critério pode piorar a manutenção. Uma alternativa é separar bancos: um Room normal para dados públicos ou reconstruíveis e um armazenamento criptografado para dados sensíveis. Outra é criptografar campos específicos antes de salvar, quando consultas SQL sobre esses campos não são necessárias.\nDataStore é bom para preferências, não para segredos por padrão DataStore Preferences é ótimo para configurações: tema, idioma, onboarding visto, filtros de tela, preferências de notificação e flags simples. Ele é mais moderno que SharedPreferences, funciona bem com coroutines e Flow, e evita vários problemas de escrita síncrona.\nMas DataStore não deve virar depósito automático de secrets. Se você precisa guardar token ou informação sensível, use uma camada criptografada ou uma solução que combine DataStore com criptografia cuidadosamente revisada. Para aprender a base de uso, veja o tutorial de DataStore Preferences com Kotlin; para segurança, trate secrets como outra categoria.\nUma divisão saudável fica assim:\nDataStore: - tema - filtros - onboarding - preferências não sensíveis TokenStore criptografado: - access token, se persistido - refresh token - session id sensível Room/SQLCipher: - entidades offline - filas de sincronização - cache com dados pessoais quando necessário Essa separação deixa a arquitetura mais legível para quem chega no time e reduz o risco de alguém salvar um secret no lugar errado por conveniência.\nArquivos, anexos e cache HTTP Muitos vazamentos locais não estão no banco. Estão em arquivos temporários, anexos, imagens redimensionadas, logs ou cache HTTP. Se o app baixa comprovantes, contratos, imagens privadas ou documentos, defina regras para armazenamento interno, criptografia, expiração e limpeza.\nNo Android, prefira armazenamento interno privado para arquivos do app. Evite salvar dados sensíveis em diretórios públicos sem necessidade. Se o usuário exporta um arquivo, deixe claro que ele saiu da proteção do sandbox do app.\nPara cache HTTP, revise a configuração do OkHttp e os headers do backend. Algumas respostas não deveriam ser armazenadas em disco. Em endpoints com dados pessoais, use Cache-Control adequado no servidor e cuidado com interceptors que gravam bodies em log. O tutorial de Retrofit com Kotlin já discute autenticação, retry e logs; a mesma disciplina vale para armazenamento local de respostas.\nBackups automáticos podem reintroduzir risco O Android pode fazer backup automático de dados do app dependendo da configuração, versão e política. Isso é útil para experiência do usuário, mas perigoso para secrets, bancos criptografados sem estratégia de chave e dados que não deveriam sobreviver a troca de aparelho.\nRevise allowBackup, regras de dataExtractionRules e exclusões de backup. Não trate backup como detalhe de manifesto. Pergunte:\ntokens entram no backup? banco local entra no backup? a chave criptográfica também entra ou fica presa ao hardware antigo? restauração em outro aparelho quebra abertura do banco? logout limpa dados que já foram copiados? Em alguns produtos, faz sentido excluir bancos e tokens de backup e reconstruir estado a partir do servidor. Em outros, como apps offline corporativos, pode haver uma estratégia própria de exportação e recuperação. O importante é não deixar o comportamento padrão decidir sozinho.\nLogout precisa limpar mais do que token Um logout seguro não remove apenas access_token. Ele deve limpar o conjunto de dados associados à sessão. Dependendo do app, isso inclui:\ntokens e session ids; banco local do usuário; filas de sincronização pendentes; anexos baixados; cache HTTP; imagens temporárias; chaves locais relacionadas à sessão; jobs agendados no WorkManager. Em Kotlin, centralize essa limpeza em um caso de uso ou coordenador de sessão:\nclass LogoutUseCase( private val tokenStore: TokenStore, private val database: AppDatabase, private val cacheCleaner: CacheCleaner, private val workManager: WorkManager, ) { suspend fun executar() { workManager.cancelAllWorkByTag(\u0026#34;sync-usuario\u0026#34;) database.clearAllTables() cacheCleaner.limparArquivosDaSessao() tokenStore.limpar() } } A ordem pode variar. Se há operações offline pendentes, talvez o produto precise avisar o usuário antes de descartar. Em apps corporativos, logout remoto ou bloqueio administrativo pode exigir limpeza imediata. Documente a decisão.\nLogs, analytics e crash reports Mesmo com banco criptografado, você pode vazar dado em log. Isso acontece quando o app imprime DTO completo, request body, token, exceção com payload, URL com query sensível ou objeto de domínio no crash report.\nRegras práticas:\nnunca logue token, senha, refresh token ou authorization header; evite logar CPF, email, telefone e endereço completos; use correlation id e endpoint lógico em vez de body inteiro; configure redaction no OkHttp logging interceptor; trate crash reports como ambiente externo; revise eventos de analytics para não enviar PII sem necessidade. Para observabilidade, o objetivo é conseguir investigar sem transformar ferramentas de monitoramento em cópia paralela do banco. Em apps Android, isso é ainda mais importante porque logs podem circular por suporte, QA, aparelho de teste e relatórios de crash.\nOffline-first e segurança: conflito real Arquitetura offline-first aumenta a quantidade de dados locais. Isso cria um conflito saudável entre experiência e segurança. Um vendedor em campo precisa abrir pedidos sem internet. Um app financeiro não deveria guardar extrato completo indefinidamente. Um app de saúde pode precisar funcionar offline, mas cada registro local tem alto risco.\nAlgumas decisões úteis:\nsalve apenas campos necessários para a experiência offline; expire dados antigos depois de uma janela clara; criptografe filas com PII ou operações sensíveis; use sync incremental para não baixar histórico desnecessário; limpe dados no logout e em bloqueio remoto; mostre ao usuário quando algo ainda está pendente de sincronização. O repository é um bom lugar para aplicar essa política. Ele já coordena Room, API, cache e fila. Em vez de deixar cada tela decidir o que guardar, o repository deve receber modelos de domínio e transformar em entidades locais com apenas os campos aprovados.\nChecklist para revisar um app Kotlin Use esta lista como ponto de partida antes de publicar ou refatorar uma área sensível:\nListe dados locais por categoria: público, pessoal, credencial, financeiro, corporativo. Separe preferências simples de secrets. Proteja tokens com Keystore ou armazenamento criptografado. Defina se Room precisa de SQLCipher ou se basta separar dados sensíveis. Revise arquivos temporários, anexos e cache HTTP. Configure backup e exclusões conscientemente. Garanta que logout limpa dados da sessão, não só token. Reduza logs, analytics e crash reports com PII. Teste atualização, reinstalação, restauração, logout e rotação de token. Documente a política para o próximo dev não quebrar por conveniência. Essa revisão conversa diretamente com temas de segurança no Spring com JWT e OAuth2, Retrofit no Android e testes Android com Kotlin. Segurança local só funciona bem quando app, API e processo de qualidade estão alinhados.\nErros comuns O primeiro erro é salvar token em SharedPreferences comum porque “o sandbox já protege”. O sandbox ajuda, mas token é credencial. Use proteção adicional quando possível.\nO segundo erro é criptografar banco e esquecer logs. Um token removido do SQLite, mas impresso por interceptor em produção, continua vazando.\nO terceiro erro é salvar dados demais offline. Se a tela só precisa dos últimos 30 itens, talvez não faça sentido manter anos de histórico no dispositivo.\nO quarto erro é não testar restauração. Banco criptografado pode abrir bem no aparelho original e falhar depois de backup/restauração se a chave não acompanha o dado.\nO quinto erro é tratar logout como navegação para tela de login. Logout é operação de segurança e limpeza de estado.\nConclusão Segurança de dados locais no Android com Kotlin é uma decisão de arquitetura. Room, DataStore, SQLCipher, EncryptedSharedPreferences e Keystore são ferramentas úteis, mas a parte mais importante é classificar dados, reduzir persistência, limpar sessão, controlar backups e evitar vazamento por logs.\nEm 2026, apps Android profissionais precisam equilibrar offline-first, performance e privacidade. O melhor caminho não é guardar tudo nem apagar tudo: é salvar apenas o necessário, proteger o que é sensível e deixar a política clara no código. Assim, o app continua rápido e útil sem transformar o dispositivo em um ponto frágil do produto.\n","permalink":"https://kotlin.dev.br/blog/seguranca-dados-locais-android-kotlin-2026/","summary":"\u003cp\u003eSegurança de dados locais no Android costuma aparecer tarde demais no projeto. O app começa guardando um token, depois adiciona cache de perfil, preferências, fila offline, histórico de pedidos, dados financeiros ou informações de saúde. Quando o produto cresce, a pergunta muda: \u003cstrong\u003eo que acontece se esse dispositivo for perdido, roubado, rooteado, restaurado de backup ou analisado por alguém com acesso físico?\u003c/strong\u003e Em apps Android feitos com Kotlin, proteger armazenamento local precisa fazer parte da arquitetura, não apenas de uma checklist antes de publicar na Play Store.\u003c/p\u003e","title":"Segurança de Dados Locais no Android com Kotlin em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaProcuramos um Desenvolvedor Backend Sênior para integrar o time da SAP Concur Travel, liderando o desenvolvimento de soluções robustas e escaláveis usando Kotlin, Java e Golang.\nResponsabilidadesArquitetar e implementar serviços backend distribuídosOtimizar infraestrutura cloud com Kubernetes e AWSIntegrar capacidades de IA generativa e RAG em aplicaçõesColaborar com times multidisciplinares para entregar soluções de alta qualidadeMentorizar desenvolvedores juniores e compartilhar conhecimento técnicoRequisitosExperiência sênior em desenvolvimento backend com Kotlin, Java ou GolangConhecimento profundo de containerização (Docker, Kubernetes)Experiência com infraestrutura AWS (EC2, EKS, DynamoDB)Familiaridade com padrões de arquitetura distribuída e microsserviçosExcelentes habilidades de comunicação e trabalho em equipeDiferenciaisExperiência com IA generativa e modelos de linguagem (LLM)Conhecimento em RAG (Retrieval-Augmented Generation)Experiência com assistentes de IA como Claude, Copilot ou ClineFamiliaridade com .NET e Model Context Protocols (MCP) ","permalink":"https://kotlin.dev.br/vagas/unewcgupn9yvxhr7-sap-backend-senior-developer-sap-concur-travel/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eProcuramos um Desenvolvedor Backend Sênior para integrar o time da SAP Concur Travel, liderando o desenvolvimento de soluções robustas e escaláveis usando Kotlin, Java e Golang.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eArquitetar e implementar serviços backend distribuídos\u003c/li\u003e\u003cli\u003eOtimizar infraestrutura cloud com Kubernetes e AWS\u003c/li\u003e\u003cli\u003eIntegrar capacidades de IA generativa e RAG em aplicações\u003c/li\u003e\u003cli\u003eColaborar com times multidisciplinares para entregar soluções de alta qualidade\u003c/li\u003e\u003cli\u003eMentorizar desenvolvedores juniores e compartilhar conhecimento técnico\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento backend com Kotlin, Java ou Golang\u003c/li\u003e\u003cli\u003eConhecimento profundo de containerização (Docker, Kubernetes)\u003c/li\u003e\u003cli\u003eExperiência com infraestrutura AWS (EC2, EKS, DynamoDB)\u003c/li\u003e\u003cli\u003eFamiliaridade com padrões de arquitetura distribuída e microsserviços\u003c/li\u003e\u003cli\u003eExcelentes habilidades de comunicação e trabalho em equipe\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com IA generativa e modelos de linguagem (LLM)\u003c/li\u003e\u003cli\u003eConhecimento em RAG (Retrieval-Augmented Generation)\u003c/li\u003e\u003cli\u003eExperiência com assistentes de IA como Claude, Copilot ou Cline\u003c/li\u003e\u003cli\u003eFamiliaridade com .NET e Model Context Protocols (MCP)\u003c/li\u003e\u003c/ul\u003e","title":"Backend Senior Developer - SAP Concur Travel"},{"content":"Sobre a vagaBuscamos um Desenvolvedor Frontend sênior para integrar o time de desenvolvimento da plataforma SAP Concur Travel, trabalhando com tecnologias modernas e em um ambiente colaborativo.\nResponsabilidadesDesenvolver e manter componentes frontend em TypeScript e ReactTrabalhar com GraphQL e Apollo Client para gerenciamento de estado e comunicação com APIsImplementar testes com Jest e React Testing LibraryOtimizar performance e build com WebpackColaborar com times backend e produto para entregar soluções de qualidadeRequisitosExperiência sênior com TypeScript e ReactConhecimento em GraphQL e Apollo ClientFamiliaridade com Redux (RTK), Jest e React Testing LibraryExperiência com ferramentas de build como WebpackConhecimento em Express para contexto de fullstackDiferenciaisExperiência com linguagens backend como Go, Java ou KotlinConhecimento em .NETExperiência com AWSFamiliaridade com ferramentas de IA como Claude Code, Cline ou CopilotLocalizaçãoHíbrido em São Leopoldo, Rio Grande do Sul.\n","permalink":"https://kotlin.dev.br/vagas/s3pk0zhrgb7wwwmk-sap-frontend-senior-developer-sap-concur-travel/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Desenvolvedor Frontend sênior para integrar o time de desenvolvimento da plataforma SAP Concur Travel, trabalhando com tecnologias modernas e em um ambiente colaborativo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter componentes frontend em TypeScript e React\u003c/li\u003e\u003cli\u003eTrabalhar com GraphQL e Apollo Client para gerenciamento de estado e comunicação com APIs\u003c/li\u003e\u003cli\u003eImplementar testes com Jest e React Testing Library\u003c/li\u003e\u003cli\u003eOtimizar performance e build com Webpack\u003c/li\u003e\u003cli\u003eColaborar com times backend e produto para entregar soluções de qualidade\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com TypeScript e React\u003c/li\u003e\u003cli\u003eConhecimento em GraphQL e Apollo Client\u003c/li\u003e\u003cli\u003eFamiliaridade com Redux (RTK), Jest e React Testing Library\u003c/li\u003e\u003cli\u003eExperiência com ferramentas de build como Webpack\u003c/li\u003e\u003cli\u003eConhecimento em Express para contexto de fullstack\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com linguagens backend como Go, Java ou Kotlin\u003c/li\u003e\u003cli\u003eConhecimento em .NET\u003c/li\u003e\u003cli\u003eExperiência com AWS\u003c/li\u003e\u003cli\u003eFamiliaridade com ferramentas de IA como Claude Code, Cline ou Copilot\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocalização\u003c/h3\u003e\u003cp\u003eHíbrido em São Leopoldo, Rio Grande do Sul.\u003c/p\u003e","title":"Frontend Senior Developer - SAP Concur Travel"},{"content":"Sobre a vagaA GFT busca uma pessoa Desenvolvedora Android Sênior para atuar em modelo híbrido, com base em Alphaville ou São Paulo.\nA posição envolve desenvolvimento mobile Android com Kotlin, Android SDK e boas práticas de arquitetura, testes e entrega contínua.\nResponsabilidadesDesenvolver e manter aplicações Android nativas com Kotlin.Trabalhar com Android SDK, MVVM e Clean Architecture.Integrar aplicações com APIs REST e serviços externos.Aplicar boas práticas de versionamento com Git e esteiras de CI/CD.Colaborar em times ágeis na definição, implementação e melhoria de funcionalidades.Apoiar qualidade técnica por meio de testes unitários e revisão de código.RequisitosExperiência sênior em desenvolvimento Android.Conhecimento sólido em Kotlin e Android SDK.Experiência com MVVM, Clean Architecture e consumo de APIs REST.Vivência com Git, testes unitários e práticas ágeis.Experiência com publicação ou manutenção de apps na Google Play.DiferenciaisExperiência com Jetpack Compose.Conhecimento em Firebase.Vivência com pipelines de CI/CD para aplicações mobile.Modelo de trabalhoVaga híbrida para atuação em Alphaville ou São Paulo.\n","permalink":"https://kotlin.dev.br/vagas/gi9u0p4c0ned28lw-gft-desenvolvedor-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA GFT busca uma pessoa Desenvolvedora Android Sênior para atuar em modelo híbrido, com base em Alphaville ou São Paulo.\u003c/p\u003e\u003cp\u003eA posição envolve desenvolvimento mobile Android com Kotlin, Android SDK e boas práticas de arquitetura, testes e entrega contínua.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android nativas com Kotlin.\u003c/li\u003e\u003cli\u003eTrabalhar com Android SDK, MVVM e Clean Architecture.\u003c/li\u003e\u003cli\u003eIntegrar aplicações com APIs REST e serviços externos.\u003c/li\u003e\u003cli\u003eAplicar boas práticas de versionamento com Git e esteiras de CI/CD.\u003c/li\u003e\u003cli\u003eColaborar em times ágeis na definição, implementação e melhoria de funcionalidades.\u003c/li\u003e\u003cli\u003eApoiar qualidade técnica por meio de testes unitários e revisão de código.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin e Android SDK.\u003c/li\u003e\u003cli\u003eExperiência com MVVM, Clean Architecture e consumo de APIs REST.\u003c/li\u003e\u003cli\u003eVivência com Git, testes unitários e práticas ágeis.\u003c/li\u003e\u003cli\u003eExperiência com publicação ou manutenção de apps na Google Play.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Jetpack Compose.\u003c/li\u003e\u003cli\u003eConhecimento em Firebase.\u003c/li\u003e\u003cli\u003eVivência com pipelines de CI/CD para aplicações mobile.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga híbrida para atuação em Alphaville ou São Paulo.\u003c/p\u003e","title":"Desenvolvedor Android Sênior"},{"content":"Sobre a vagaA GFT busca uma pessoa Desenvolvedora Android Sênior para atuar em modelo híbrido, com base em Alphaville ou São Paulo.\nResponsabilidadesDesenvolver e evoluir aplicações Android usando Kotlin e Android SDK.Trabalhar com arquitetura MVVM, Clean Architecture e integração com APIs REST.Implementar interfaces e funcionalidades com Jetpack Compose.Aplicar boas práticas de versionamento com Git, testes automatizados e CI/CD.Apoiar publicação e manutenção de aplicativos na Google Play.Atuar em rotinas ágeis com Kanban, SAFe e práticas de SDLC.RequisitosExperiência sênior em desenvolvimento Android.Conhecimento sólido em Kotlin, Android SDK, MVVM e Clean Architecture.Experiência com REST, Firebase, Git, testes automatizados e pipelines de CI/CD.Familiaridade com governança de APIs e boas práticas de engenharia de software.DiferenciaisExperiência com ML-Ops em projetos mobile.Vivência com Jetpack Compose em aplicações em produção. ","permalink":"https://kotlin.dev.br/vagas/wdrk22hw0trbg908-gft-desenvolvedor-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA GFT busca uma pessoa Desenvolvedora Android Sênior para atuar em modelo híbrido, com base em Alphaville ou São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e evoluir aplicações Android usando Kotlin e Android SDK.\u003c/li\u003e\u003cli\u003eTrabalhar com arquitetura MVVM, Clean Architecture e integração com APIs REST.\u003c/li\u003e\u003cli\u003eImplementar interfaces e funcionalidades com Jetpack Compose.\u003c/li\u003e\u003cli\u003eAplicar boas práticas de versionamento com Git, testes automatizados e CI/CD.\u003c/li\u003e\u003cli\u003eApoiar publicação e manutenção de aplicativos na Google Play.\u003c/li\u003e\u003cli\u003eAtuar em rotinas ágeis com Kanban, SAFe e práticas de SDLC.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin, Android SDK, MVVM e Clean Architecture.\u003c/li\u003e\u003cli\u003eExperiência com REST, Firebase, Git, testes automatizados e pipelines de CI/CD.\u003c/li\u003e\u003cli\u003eFamiliaridade com governança de APIs e boas práticas de engenharia de software.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com ML-Ops em projetos mobile.\u003c/li\u003e\u003cli\u003eVivência com Jetpack Compose em aplicações em produção.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android Sênior"},{"content":"Sobre a vagaA GFT busca uma pessoa Desenvolvedora Android Sênior para atuação remota, com base em Medellín, Antioquia, Colômbia.\nRequisitosExperiência sênior em desenvolvimento Android.Conhecimento em Kotlin e Java.Experiência com publicação ou manutenção de apps no Google Play.Nível de inglês B1+. ","permalink":"https://kotlin.dev.br/vagas/nm7cduvsv1rea8u1-gft-desenvolvedor-android-senior-ingles-b1/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA GFT busca uma pessoa Desenvolvedora Android Sênior para atuação remota, com base em Medellín, Antioquia, Colômbia.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eJava\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com publicação ou manutenção de apps no \u003cstrong\u003eGoogle Play\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eNível de inglês B1+.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android Sênior (inglês B1+)"},{"content":"Sobre a vagaBuscamos um Expert Software Architect sênior para liderar a arquitetura técnica da plataforma SAP Concur Travel. Você será responsável por desenhar soluções escaláveis e resilientes, integrando tecnologias modernas como Kubernetes, AWS e modelos de linguagem.\nResponsabilidadesDefinir e evoluir a arquitetura de sistemas distribuídos para Concur TravelOrientar equipes de desenvolvimento em decisões tecnológicas estratégicasIntegrar soluções de IA generativa (LLM, RAG, Model Context Protocols) na plataformaGarantir conformidade com padrões de segurança (FedRAMP, PCI, SOC1, SOC2)Avaliar e implementar melhorias de performance e resiliência em infraestrutura cloudRequisitosExperiência sênior em arquitetura de software e sistemas distribuídosProficiência com Kotlin, Java e GoExpertise em containerização (Docker, Helm) e orquestração (Kubernetes)Conhecimento sólido de AWS (EC2, EKS, DynamoDB)Experiência com integrações de IA generativa e LLMsFamiliaridade com compliance e segurança em nível enterpriseDiferenciaisExperiência com Model Context Protocols (MCP) e RAGConhecimento de ferramentas como Claude Code e ClineTrajetória em produtos SaaS de viagem ou expense management ","permalink":"https://kotlin.dev.br/vagas/zqzc8ek4o49v9oly-sap-expert-software-architect-sap-concur-travel/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Expert Software Architect sênior para liderar a arquitetura técnica da plataforma SAP Concur Travel. Você será responsável por desenhar soluções escaláveis e resilientes, integrando tecnologias modernas como Kubernetes, AWS e modelos de linguagem.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDefinir e evoluir a arquitetura de sistemas distribuídos para Concur Travel\u003c/li\u003e\u003cli\u003eOrientar equipes de desenvolvimento em decisões tecnológicas estratégicas\u003c/li\u003e\u003cli\u003eIntegrar soluções de IA generativa (LLM, RAG, Model Context Protocols) na plataforma\u003c/li\u003e\u003cli\u003eGarantir conformidade com padrões de segurança (FedRAMP, PCI, SOC1, SOC2)\u003c/li\u003e\u003cli\u003eAvaliar e implementar melhorias de performance e resiliência em infraestrutura cloud\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em arquitetura de software e sistemas distribuídos\u003c/li\u003e\u003cli\u003eProficiência com Kotlin, Java e Go\u003c/li\u003e\u003cli\u003eExpertise em containerização (Docker, Helm) e orquestração (Kubernetes)\u003c/li\u003e\u003cli\u003eConhecimento sólido de AWS (EC2, EKS, DynamoDB)\u003c/li\u003e\u003cli\u003eExperiência com integrações de IA generativa e LLMs\u003c/li\u003e\u003cli\u003eFamiliaridade com compliance e segurança em nível enterprise\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Model Context Protocols (MCP) e RAG\u003c/li\u003e\u003cli\u003eConhecimento de ferramentas como Claude Code e Cline\u003c/li\u003e\u003cli\u003eTrajetória em produtos SaaS de viagem ou expense management\u003c/li\u003e\u003c/ul\u003e","title":"Expert Software Architect - SAP Concur Travel"},{"content":"Sobre a vagaO C6 Bank busca uma Pessoa Engenheira de Plataformas Sênior para atuar com Developer Experience em São Paulo, em modelo presencial.\nTecnologias mencionadasKotlin, Java, Python e GoAWS, GCP e OCITerraform, Kubernetes e DockerLinux e WindowsCI/CD, Git e pipelinesDevOps, observabilidade, logging e tracingSenioridadeNível sênior.\nLocal de trabalhoSão Paulo, São Paulo, Brasil. Modelo presencial.\n","permalink":"https://kotlin.dev.br/vagas/ruy8chucl8khwhic-c6-bank-pessoa-engenheira-de-plataformas-senior-developer-exper/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma Pessoa Engenheira de Plataformas Sênior para atuar com Developer Experience em São Paulo, em modelo presencial.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java, Python e Go\u003c/li\u003e\u003cli\u003eAWS, GCP e OCI\u003c/li\u003e\u003cli\u003eTerraform, Kubernetes e Docker\u003c/li\u003e\u003cli\u003eLinux e Windows\u003c/li\u003e\u003cli\u003eCI/CD, Git e pipelines\u003c/li\u003e\u003cli\u003eDevOps, observabilidade, logging e tracing\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade\u003c/h3\u003e\u003cp\u003eNível sênior.\u003c/p\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eSão Paulo, São Paulo, Brasil. Modelo presencial.\u003c/p\u003e","title":"Pessoa Engenheira de Plataformas Sênior | Developer Experience"},{"content":"Rate limiting é uma daquelas decisões de backend que parecem detalhe até o primeiro pico de tráfego, abuso de API ou integração mal comportada. Em uma aplicação Kotlin exposta na internet, limitar requisições protege infraestrutura, banco de dados, serviços externos, filas, custos em cloud e, principalmente, a experiência dos usuários legítimos. Sem limite, um único cliente com bug pode consumir a mesma capacidade que centenas de usuários reais.\nPara quem trabalha com Kotlin para backend, rate limiting deve entrar no mesmo grupo de autenticação, autorização, timeout, retry, observabilidade e cache: não é enfeite de produção, é parte do contrato operacional da API. Este guia mostra como pensar limites em Spring Boot, Ktor e Redis, com exemplos práticos e trade-offs que aparecem em times brasileiros usando Kotlin em APIs REST, microsserviços e produtos SaaS.\nO que rate limiting resolve Rate limiting controla quantas ações uma identidade pode executar em uma janela de tempo. Essa identidade pode ser um IP, usuário autenticado, tenant, chave de API, rota, token interno ou combinação desses elementos. A regra mais simples é: \u0026ldquo;no máximo 100 requisições por minuto por usuário\u0026rdquo;. Em sistemas reais, a regra costuma variar por endpoint, plano contratado e criticidade da operação.\nEle ajuda em vários cenários:\nevitar força bruta em login, recuperação de senha e endpoints sensíveis; impedir scraping agressivo de catálogos, vagas ou dados públicos; proteger chamadas caras que acessam banco, IA, pagamento ou parceiro externo; preservar qualidade de serviço durante picos; transformar abuso em resposta previsível com HTTP 429 Too Many Requests. Rate limiting não substitui Spring Security com JWT e OAuth2, WAF, validação de entrada ou observabilidade. Ele complementa essas camadas. Um endpoint autenticado ainda pode ser abusado por um token legítimo. Uma chamada pública ainda precisa diferenciar tráfego normal de automação agressiva.\nEscolha a chave correta O erro mais comum é limitar apenas por IP. Isso funciona para uma primeira defesa, mas tem problemas: muitos usuários podem compartilhar o mesmo IP corporativo, usuários móveis trocam de IP com frequência, proxies escondem origem e atacantes podem distribuir chamadas. Sempre que possível, combine sinais.\nPara endpoints autenticados, uma chave melhor costuma ser usuario:{id}:rota:{nome} ou tenant:{id}:rota:{nome}. Para APIs B2B, use a chave de API ou client id. Para endpoints públicos, use IP normalizado, user agent apenas como sinal auxiliar e limites mais conservadores em rotas críticas.\nTambém pense em granularidade. Um limite global por usuário protege a plataforma inteira, mas pode bloquear ações legítimas se uma tela faz muitas chamadas leves. Um limite por rota protege operações caras, mas não impede abuso distribuído entre muitos endpoints. Em produção, uma combinação costuma funcionar melhor: limite global, limite por endpoint sensível e limite especial para operações com efeito colateral.\nAlgoritmos comuns Existem várias formas de aplicar limites. As mais usadas em APIs Kotlin são janela fixa, janela deslizante e token bucket.\nJanela fixa é simples: contar chamadas entre 10:00:00 e 10:00:59, depois reiniciar. É fácil de implementar com Redis, mas pode permitir rajadas na virada da janela. Se o limite é 100 por minuto, um cliente pode fazer 100 chamadas às 10:00:59 e mais 100 às 10:01:00.\nJanela deslizante reduz esse problema ao considerar os últimos 60 segundos reais. É mais justa, mas exige estrutura de dados e limpeza mais cuidadosas. Token bucket permite acumular uma quantidade limitada de \u0026ldquo;fichas\u0026rdquo; e recarregar ao longo do tempo. Ele lida bem com pequenas rajadas sem liberar abuso sustentado.\nPara começar, janela fixa com limites prudentes e métricas já é melhor que nada. Para produtos com tráfego alto, planos pagos ou risco financeiro, token bucket ou janela deslizante trazem mais controle.\nImplementação simples com Redis Redis em Kotlin é uma escolha comum porque INCR e expiração são rápidos e atômicos. Um serviço básico em Spring Boot pode ficar assim:\n@Service class RateLimitService( private val redis: StringRedisTemplate, ) { fun permitir(chave: String, limite: Long, janela: Duration): Boolean { val contador = redis.opsForValue().increment(chave) ?: return false if (contador == 1L) { redis.expire(chave, janela) } return contador \u0026lt;= limite } } Esse exemplo é intencionalmente pequeno. Em produção, prefira executar incremento e TTL em script Lua ou biblioteca pronta para evitar inconsistência se o processo cair entre INCR e EXPIRE. Ainda assim, ele mostra a mecânica: cada chave recebe uma contagem e uma expiração curta.\nUm filtro Spring pode aplicar a regra antes do controller:\n@Component class ApiRateLimitFilter( private val rateLimit: RateLimitService, ) : OncePerRequestFilter() { override fun doFilterInternal( request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain, ) { val user = request.userPrincipal?.name ?: request.remoteAddr val key = \u0026#34;rate:v1:$user:${request.method}:${request.requestURI}\u0026#34; if (!rateLimit.permitir(key, limite = 120, janela = Duration.ofMinutes(1))) { response.status = 429 response.setHeader(\u0026#34;Retry-After\u0026#34;, \u0026#34;60\u0026#34;) response.writer.write(\u0026#34;Limite de requisições excedido\u0026#34;) return } chain.doFilter(request, response) } } Não use o caminho completo sem cuidado se ele contém IDs, slugs ou parâmetros muito variados. Isso pode criar milhões de chaves. Normalmente é melhor mapear rotas para nomes estáveis, como login, criar-pedido, buscar-catalogo ou webhook-parceiro.\nRate limiting no Ktor Em Ktor, a ideia pode ser implementada como plugin, interceptor de rota ou função reutilizável. Para começar de forma explícita:\nsuspend fun PipelineContext\u0026lt;Unit, ApplicationCall\u0026gt;.aplicarRateLimit( redis: RedisRateLimiter, limite: Long, janela: Duration, ) { val principal = call.principal\u0026lt;UserIdPrincipal\u0026gt;()?.name val origem = principal ?: call.request.origin.remoteHost val rota = call.request.httpMethod.value + \u0026#34;:\u0026#34; + call.request.path() val chave = \u0026#34;rate:v1:$origem:$rota\u0026#34; if (!redis.permitir(chave, limite, janela)) { call.response.header(HttpHeaders.RetryAfter, janela.seconds.toString()) call.respond(HttpStatusCode.TooManyRequests, \u0026#34;Limite de requisições excedido\u0026#34;) finish() } } Depois, chame a função nas rotas mais sensíveis ou encapsule em um plugin interno. Para APIs com coroutines, evite bloqueios longos dentro do limitador. Use cliente Redis compatível com o modelo assíncrono da aplicação ou isole chamadas bloqueantes em dispatcher adequado.\nLimites diferentes por operação Nem toda rota merece o mesmo número. GET /produtos pode aceitar volume maior, especialmente se há cache. POST /login, POST /checkout, POST /webhooks/parceiro e POST /relatorios/exportar precisam de regras próprias. Operações idempotentes e baratas toleram mais tráfego; operações com efeito colateral, custo externo ou risco de segurança pedem limites menores.\nUm bom ponto de partida:\nlogin: poucas tentativas por minuto por IP e por conta; recuperação de senha: limite baixo por e-mail e por IP; APIs autenticadas comuns: limite por usuário e por tenant; endpoints de escrita: limite menor que leitura; integrações externas: limite alinhado ao contrato do parceiro; jobs manuais ou exportações: limite por usuário e fila assíncrona. Se o backend chama serviços externos, combine rate limiting de entrada com cliente HTTP resiliente. O guia de Ktor Client com timeout, retry e circuit breaker mostra por que retry sem limite pode amplificar incidentes. Um 429 bem aplicado é melhor que deixar todas as chamadas entrarem, repetirem e derrubarem a dependência.\nObservabilidade e resposta HTTP Rate limiting sem métrica vira chute. Registre contadores por regra, rota e resultado: permitido, bloqueado, erro no Redis e fallback aplicado. Não grave dados sensíveis na chave de log; use IDs internos, hash ou rótulos controlados. Em dashboards, acompanhe taxa de 429, top rotas bloqueadas, tenants mais limitados e latência do limitador.\nTambém devolva uma resposta útil. O status correto é 429 Too Many Requests. O header Retry-After ajuda clientes bem comportados a esperar. Em APIs públicas, documente limites e mensagens. Em APIs internas, trate limite como contrato: consumidor que excede limite precisa ajustar batch, cache, paginação ou backoff.\nPara investigar incidentes, integre esses eventos à sua camada de observabilidade em Kotlin. Um aumento súbito de bloqueios pode ser ataque, bug de frontend, app mobile antigo, parceiro sem backoff ou campanha de marketing bem-sucedida. A resposta operacional muda conforme a causa.\nCuidados de produção Evite falhar fechado sem reflexão. Se Redis fica indisponível, bloquear todo tráfego pode transformar falha pequena em outage total. Permitir tudo também pode expor o sistema no pior momento. A política depende da rota: login pode falhar fechado com mensagem temporária; leitura pública pode falhar aberto com limite local; checkout talvez precise fallback conservador e alerta imediato.\nUse namespaces versionados nas chaves, como rate:v1, para mudar regras sem misturar contadores antigos. Defina TTL em todas as chaves. Evite cardinalidade explosiva. Faça testes de carga com cenários de rajada. Documente exceções para health checks, webhooks confiáveis e tarefas internas. E revise limites com base em dados reais, não apenas opinião.\nCarreira e próximos passos Rate limiting é um tema pequeno no código e grande na maturidade operacional. Em entrevistas para backend Kotlin, ele ajuda a demonstrar que você entende segurança, performance, resiliência, Redis, HTTP e experiência de usuário. Para portfólio, implemente uma API com Spring Boot ou Ktor, autenticação, Redis, testes e métricas, depois documente os limites escolhidos.\nQuem quer comparar stacks pode estudar como Go costuma resolver middlewares HTTP de alta concorrência em Go para backend. A lógica de produto é parecida; o que muda são bibliotecas, ergonomia e modelo de execução. Em Kotlin, a vantagem está em combinar ecossistema JVM maduro, Spring Boot quando há necessidade corporativa e Ktor quando simplicidade e coroutines são prioridades.\nO próximo passo prático é escolher três endpoints do seu projeto e escrever uma tabela: identidade usada no limite, janela, quantidade, resposta HTTP, métrica e fallback. Se essa tabela não existe, o rate limiting ainda está implícito. Torná-lo explícito é uma das formas mais baratas de deixar uma API Kotlin mais preparada para produção.\n","permalink":"https://kotlin.dev.br/blog/rate-limiting-kotlin-spring-ktor-2026/","summary":"\u003cp\u003eRate limiting é uma daquelas decisões de backend que parecem detalhe até o primeiro pico de tráfego, abuso de API ou integração mal comportada. Em uma aplicação Kotlin exposta na internet, limitar requisições protege infraestrutura, banco de dados, serviços externos, filas, custos em cloud e, principalmente, a experiência dos usuários legítimos. Sem limite, um único cliente com bug pode consumir a mesma capacidade que centenas de usuários reais.\u003c/p\u003e\n\u003cp\u003ePara quem trabalha com \u003ca href=\"/guias/kotlin-para-backend/\"\u003eKotlin para backend\u003c/a\u003e, rate limiting deve entrar no mesmo grupo de autenticação, autorização, timeout, retry, observabilidade e cache: não é enfeite de produção, é parte do contrato operacional da API. Este guia mostra como pensar limites em Spring Boot, Ktor e Redis, com exemplos práticos e trade-offs que aparecem em times brasileiros usando Kotlin em APIs REST, microsserviços e produtos SaaS.\u003c/p\u003e","title":"Rate Limiting em Kotlin: Spring Boot, Ktor e Redis em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA CI\u0026T busca uma pessoa Android Engineer Pleno com foco em IA para atuação híbrida em Campinas, São Paulo.\nA vaga envolve desenvolvimento mobile Android com Kotlin e integração com serviços e APIs em ambiente cloud.\nResponsabilidadesDesenvolver e manter aplicações Android usando Kotlin.Integrar aplicações mobile com APIs REST e serviços em AWS.Trabalhar com programação assíncrona usando Coroutines, Flow e RxJava.Aplicar padrões de arquitetura como MVVM e Clean Architecture.Colaborar com times multidisciplinares em entregas de produto.RequisitosExperiência em desenvolvimento Android com Kotlin.Conhecimento de APIs REST.Experiência com Coroutines, Flow ou RxJava.Conhecimento de MVVM e Clean Architecture.Disponibilidade para atuação híbrida em Campinas.TecnologiasKotlinAWSREST APIsCoroutinesFlowRxJavaMVVMClean ArchitectureDynamoDBIoT CoreAPI Gateway ","permalink":"https://kotlin.dev.br/vagas/2jbn2f7eydslrog6-ci-t-android-engineer-com-foco-em-ia-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T busca uma pessoa Android Engineer Pleno com foco em IA para atuação híbrida em Campinas, São Paulo.\u003c/p\u003e\u003cp\u003eA vaga envolve desenvolvimento mobile Android com Kotlin e integração com serviços e APIs em ambiente cloud.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android usando Kotlin.\u003c/li\u003e\u003cli\u003eIntegrar aplicações mobile com APIs REST e serviços em AWS.\u003c/li\u003e\u003cli\u003eTrabalhar com programação assíncrona usando Coroutines, Flow e RxJava.\u003c/li\u003e\u003cli\u003eAplicar padrões de arquitetura como MVVM e Clean Architecture.\u003c/li\u003e\u003cli\u003eColaborar com times multidisciplinares em entregas de produto.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento Android com Kotlin.\u003c/li\u003e\u003cli\u003eConhecimento de APIs REST.\u003c/li\u003e\u003cli\u003eExperiência com Coroutines, Flow ou RxJava.\u003c/li\u003e\u003cli\u003eConhecimento de MVVM e Clean Architecture.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação híbrida em Campinas.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eREST APIs\u003c/li\u003e\u003cli\u003eCoroutines\u003c/li\u003e\u003cli\u003eFlow\u003c/li\u003e\u003cli\u003eRxJava\u003c/li\u003e\u003cli\u003eMVVM\u003c/li\u003e\u003cli\u003eClean Architecture\u003c/li\u003e\u003cli\u003eDynamoDB\u003c/li\u003e\u003cli\u003eIoT Core\u003c/li\u003e\u003cli\u003eAPI Gateway\u003c/li\u003e\u003c/ul\u003e","title":"Android Engineer com foco em IA, Pleno"},{"content":"Sobre a vagaA CI\u0026amp;T busca um(a) Arquiteto(a) Principal de Software com foco em Mobile para atuação remota, com base em São Paulo ou Campinas.\nResponsabilidadesDefinir e evoluir arquiteturas para soluções mobile.Atuar com integrações via APIs e arquitetura de microsserviços.Apoiar decisões técnicas envolvendo Kotlin, Swift e serviços em AWS.Colaborar com times multidisciplinares na entrega de soluções escaláveis.Avaliar o uso de ferramentas de IA no ciclo de desenvolvimento.RequisitosExperiência com arquitetura de software para aplicações mobile.Conhecimento em Kotlin e Swift.Experiência com AWS, APIs e microsserviços.Capacidade de orientar decisões técnicas e comunicar trade-offs.Modelo de trabalhoVaga remota para profissionais em São Paulo ou Campinas.\n","permalink":"https://kotlin.dev.br/vagas/7551ewrgh1trjha6-ci-t-arquiteto-a-principal-de-software-mobile/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026amp;T busca um(a) Arquiteto(a) Principal de Software com foco em Mobile para atuação remota, com base em São Paulo ou Campinas.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDefinir e evoluir arquiteturas para soluções mobile.\u003c/li\u003e\u003cli\u003eAtuar com integrações via APIs e arquitetura de microsserviços.\u003c/li\u003e\u003cli\u003eApoiar decisões técnicas envolvendo Kotlin, Swift e serviços em AWS.\u003c/li\u003e\u003cli\u003eColaborar com times multidisciplinares na entrega de soluções escaláveis.\u003c/li\u003e\u003cli\u003eAvaliar o uso de ferramentas de IA no ciclo de desenvolvimento.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com arquitetura de software para aplicações mobile.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin e Swift.\u003c/li\u003e\u003cli\u003eExperiência com AWS, APIs e microsserviços.\u003c/li\u003e\u003cli\u003eCapacidade de orientar decisões técnicas e comunicar trade-offs.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais em São Paulo ou Campinas.\u003c/p\u003e","title":"Arquiteto(a) Principal de Software (Mobile)"},{"content":"Sobre a vagaA Amazon busca uma pessoa Desenvolvedora de Software II para atuar no time IES LATECH \u0026 GIS em Belo Horizonte, Minas Gerais.\nFormato e senioridadeSenioridade: pleno.Modelo de trabalho: presencial.Local: Belo Horizonte, Minas Gerais, Brasil.Tecnologias mencionadasA vaga menciona atuação com uma stack poliglota, incluindo Kotlin, Java, Python, Go, JavaScript, C, C++ e C#.\nObservaçãoA descrição detalhada de responsabilidades, requisitos e benefícios não foi fornecida no anúncio original.\n","permalink":"https://kotlin.dev.br/vagas/hgmfqrsys0w7m0om-amazon-desenvolvedor-de-software-ii-ies-latech-gis/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Amazon busca uma pessoa Desenvolvedora de Software II para atuar no time IES LATECH \u0026 GIS em Belo Horizonte, Minas Gerais.\u003c/p\u003e\u003ch3\u003eFormato e senioridade\u003c/h3\u003e\u003cul\u003e\u003cli\u003eSenioridade: pleno.\u003c/li\u003e\u003cli\u003eModelo de trabalho: presencial.\u003c/li\u003e\u003cli\u003eLocal: Belo Horizonte, Minas Gerais, Brasil.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cp\u003eA vaga menciona atuação com uma stack poliglota, incluindo Kotlin, Java, Python, Go, JavaScript, C, C++ e C#.\u003c/p\u003e\u003ch3\u003eObservação\u003c/h3\u003e\u003cp\u003eA descrição detalhada de responsabilidades, requisitos e benefícios não foi fornecida no anúncio original.\u003c/p\u003e","title":"Desenvolvedor de Software II, IES LATECH \u0026 GIS"},{"content":"Segurança em backend Kotlin raramente começa como o tema mais empolgante do projeto, mas costuma ser uma das primeiras áreas cobradas quando a aplicação sai do ambiente local. Login, autorização por papel, tokens JWT, integração com provedor OAuth2, proteção de endpoints administrativos, testes de acesso e logs sem dados sensíveis aparecem em APIs reais, entrevistas e vagas backend no Brasil.\nPara quem já trabalha com Kotlin e Spring Boot, o caminho mais comum é usar Spring Security. Ele é maduro, integra bem com o ecossistema JVM e funciona tanto para APIs REST simples quanto para sistemas corporativos conectados a Keycloak, Auth0, Cognito, Microsoft Entra ID ou outro provedor OpenID Connect. A dificuldade não é instalar a dependência. A dificuldade é configurar apenas o necessário, sem transformar a aplicação em um labirinto de filtros, annotations e exceções difíceis de debugar.\nEste guia mostra uma abordagem prática para APIs Kotlin em 2026: quando JWT faz sentido, como configurar um resource server OAuth2, onde colocar roles, como testar regras de acesso e quais cuidados evitam problemas comuns em produção.\nJWT não é sessão mágica JWT, ou JSON Web Token, é um formato assinado para carregar claims sobre uma identidade. Em APIs modernas, ele costuma aparecer no header Authorization:\nAuthorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... O token pode trazer sub, email, scope, roles, tenant, expiração e outras informações. A API valida a assinatura e decide se aquela chamada pode continuar. Isso evita consultar o banco em toda requisição só para saber quem é o usuário, mas também cria responsabilidades importantes.\nUm JWT emitido não deve ser tratado como dado editável. Se você coloca permissões demais nele, qualquer mudança de autorização só vale quando o token expira ou é revogado por outro mecanismo. Se coloca dados sensíveis, esses dados podem aparecer em logs, ferramentas de debug ou clientes comprometidos. Se usa expiração longa demais, o risco de vazamento cresce. Por isso, tokens de acesso devem ser curtos e objetivos.\nPara aplicações web com sessão tradicional, Redis pode guardar sessão curta, mas isso não substitui JWT em APIs stateless nem resolve autorização sozinho. Cada modelo tem trade-offs. JWT é bom para APIs distribuídas e integrações entre serviços; sessão centralizada é boa quando você controla o servidor web e precisa invalidar estado imediatamente.\nDependências mínimas no Spring Boot Em um backend Kotlin com Gradle, uma API REST que valida tokens OAuth2 geralmente precisa de:\ndependencies { implementation(\u0026#34;org.springframework.boot:spring-boot-starter-web\u0026#34;) implementation(\u0026#34;org.springframework.boot:spring-boot-starter-security\u0026#34;) implementation(\u0026#34;org.springframework.boot:spring-boot-starter-oauth2-resource-server\u0026#34;) implementation(\u0026#34;com.fasterxml.jackson.module:jackson-module-kotlin\u0026#34;) testImplementation(\u0026#34;org.springframework.boot:spring-boot-starter-test\u0026#34;) testImplementation(\u0026#34;org.springframework.security:spring-security-test\u0026#34;) } O resource-server é a peça que faz sua API validar tokens emitidos por outro sistema. A API não precisa saber a senha do usuário. Ela precisa confiar no emissor, validar assinatura, checar expiração e mapear claims para permissões internas.\nNo application.yml, configure o emissor:\nspring: security: oauth2: resourceserver: jwt: issuer-uri: https://auth.exemplo.com/realms/produto Com issuer-uri, o Spring busca metadados OpenID Connect e chaves públicas automaticamente. Em produção, isso exige rede confiável no boot ou cache adequado das chaves. Para ambientes sensíveis, documente o que acontece se o provedor de identidade ficar indisponível.\nConfigurando rotas públicas e protegidas Desde as versões modernas do Spring Security, a configuração com Kotlin fica mais clara usando beans. Um exemplo inicial:\n@Configuration @EnableWebSecurity class SecurityConfig { @Bean fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { return http .csrf { it.disable() } .authorizeHttpRequests { auth -\u0026gt; auth.requestMatchers(\u0026#34;/actuator/health\u0026#34;, \u0026#34;/docs/**\u0026#34;).permitAll() auth.requestMatchers(HttpMethod.GET, \u0026#34;/api/produtos/**\u0026#34;).hasAuthority(\u0026#34;SCOPE_produtos:ler\u0026#34;) auth.requestMatchers(HttpMethod.POST, \u0026#34;/api/produtos/**\u0026#34;).hasAuthority(\u0026#34;SCOPE_produtos:escrever\u0026#34;) auth.requestMatchers(\u0026#34;/api/admin/**\u0026#34;).hasRole(\u0026#34;ADMIN\u0026#34;) auth.anyRequest().authenticated() } .oauth2ResourceServer { resourceServer -\u0026gt; resourceServer.jwt { } } .build() } } Desabilitar CSRF faz sentido em APIs stateless chamadas por clientes que usam Authorization: Bearer. Não copie essa linha para aplicações web com formulário e sessão sem entender o impacto. Segurança boa depende do tipo de cliente, não de receita universal.\nOutro detalhe é a diferença entre hasAuthority(\u0026quot;SCOPE_x\u0026quot;) e hasRole(\u0026quot;ADMIN\u0026quot;). O Spring trata roles com prefixo ROLE_ internamente. Scopes OAuth2 costumam virar authorities com prefixo SCOPE_. Misturar os dois sem padrão é uma fonte comum de bug: o token parece correto, mas o endpoint retorna 403 porque a aplicação esperava outro nome.\nModelando claims para o domínio Nem toda permissão precisa aparecer como role global. Em muitos sistemas, a autorização depende de contexto: usuário pode editar o próprio perfil, gestor pode ver dados do time, administrador pode alterar configurações e um serviço interno pode executar tarefas batch. Tentar representar tudo como ADMIN, USER e MANAGER costuma ficar pobre rapidamente.\nUma abordagem prática é separar três camadas:\nAutenticação: quem é o usuário ou serviço. Autorização técnica: quais scopes ou roles permitem acessar uma rota. Autorização de domínio: se aquele usuário pode agir sobre aquele recurso específico. Exemplo: SCOPE_pedidos:ler permite chamar GET /api/pedidos/{id}, mas a service ainda precisa validar se o pedido pertence ao usuário, ao tenant ou ao grupo permitido. Essa regra pertence ao domínio, não ao filtro HTTP.\n@Service class PedidoService( private val repository: PedidoRepository, ) { fun buscarPedido(id: UUID, usuario: UsuarioAutenticado): PedidoDto { val pedido = repository.findById(id) ?: throw PedidoNaoEncontradoException(id) if (pedido.clienteId != usuario.clienteId \u0026amp;\u0026amp; !usuario.admin) { throw AcessoNegadoAoPedidoException(id) } return pedido.toDto() } } Essa separação melhora testes e reduz acoplamento. O controller e o filtro garantem que a chamada veio autenticada; a service garante que a regra de negócio foi respeitada.\nExtraindo usuário autenticado em Kotlin Em controllers Spring MVC, você pode acessar o token com @AuthenticationPrincipal:\n@RestController @RequestMapping(\u0026#34;/api/pedidos\u0026#34;) class PedidoController( private val service: PedidoService, ) { @GetMapping(\u0026#34;/{id}\u0026#34;) fun buscar( @PathVariable id: UUID, @AuthenticationPrincipal jwt: Jwt, ): PedidoDto { val usuario = UsuarioAutenticado( id = UUID.fromString(jwt.subject), email = jwt.getClaimAsString(\u0026#34;email\u0026#34;), clienteId = UUID.fromString(jwt.getClaimAsString(\u0026#34;cliente_id\u0026#34;)), admin = jwt.getClaimAsStringList(\u0026#34;roles\u0026#34;)?.contains(\u0026#34;admin\u0026#34;) == true, ) return service.buscarPedido(id, usuario) } } Para evitar repetição, muitos times criam um resolver, extension function ou adapter pequeno que converte Jwt para um tipo do domínio. O importante é não espalhar getClaimAsString(\u0026quot;cliente_id\u0026quot;) por dezenas de controllers. Claims são contrato de integração; se mudam, você quer ajustar em poucos lugares.\nTambém vale validar nulidade com cuidado. Kotlin ajuda, mas claims vêm de payload externo. Mesmo token assinado pode não ter a claim que sua aplicação espera. Falhe de forma clara, com erro 401 ou 403 conforme o caso, e registre logs suficientes para investigação sem imprimir o token completo.\nTestes de segurança não são opcionais Se uma regra de acesso é importante, ela precisa de teste. O pacote spring-security-test permite simular usuários e JWTs em testes MVC:\n@WebMvcTest(PedidoController::class) class PedidoControllerSecurityTest( @Autowired private val mockMvc: MockMvc, ) { @Test fun `bloqueia request sem token`() { mockMvc.get(\u0026#34;/api/pedidos/11111111-1111-1111-1111-111111111111\u0026#34;) .andExpect { status { isUnauthorized() } } } @Test fun `permite leitura com scope correto`() { mockMvc.get(\u0026#34;/api/pedidos/11111111-1111-1111-1111-111111111111\u0026#34;) { with(jwt().authorities(SimpleGrantedAuthority(\u0026#34;SCOPE_pedidos:ler\u0026#34;))) }.andExpect { status { isOk() } } } } Em APIs críticas, teste também 403: token válido, usuário autenticado, mas permissão insuficiente. Esse cenário pega erros que um teste feliz não vê. Combine esses testes com o guia de testes em Kotlin e com JUnit 5 e MockK para cobrir a regra de domínio separadamente.\nErros comuns em produção O primeiro erro é confiar no frontend. Esconder botão no app ou na página web melhora experiência, mas não protege a API. Toda decisão sensível precisa ser validada no backend.\nO segundo erro é usar JWT como banco de dados. Token não deve carregar perfil completo, lista enorme de permissões, preferências, documento, endereço ou dados que mudam com frequência. Use claims mínimas e busque dados de domínio quando necessário.\nO terceiro erro é logar demais. Nunca registre token inteiro, senha, refresh token, secret, authorization code ou payload sensível. Logs de segurança devem ajudar investigação: sub, tenant, rota, status, correlation id e motivo resumido costumam ser suficientes. Para instrumentação mais ampla, conecte essa disciplina ao artigo de observabilidade em Kotlin.\nO quarto erro é tratar 401 e 403 como iguais. 401 Unauthorized indica que a requisição não está autenticada ou o token é inválido. 403 Forbidden indica que a identidade foi reconhecida, mas não tem permissão. Essa diferença ajuda cliente, suporte e monitoramento.\nO quinto erro é não documentar o contrato de segurança. Se sua API usa OpenAPI, descreva o esquema bearer e quais endpoints exigem quais scopes. O tutorial de OpenAPI e Swagger no Ktor é focado em Ktor, mas a disciplina de contrato vale igualmente para Spring.\nChecklist para uma API Kotlin segura Antes de colocar uma API Spring Security em produção, revise:\ntokens de acesso têm expiração curta; refresh tokens não são aceitos em endpoints de API comum; issuer, audience e assinatura são validados; endpoints públicos estão listados explicitamente; rotas administrativas exigem role ou scope separado; regra de domínio não depende só do filtro HTTP; testes cobrem sem token, token inválido, permissão insuficiente e sucesso; logs não imprimem secrets nem tokens completos; métricas separam 401, 403 e erro de provedor de identidade; documentação informa autenticação e scopes esperados. Se o time trabalha com múltiplas linguagens, vale comparar como outras stacks resolvem os mesmos problemas. Em Go, é comum montar middlewares HTTP explícitos para JWT. Em Python, FastAPI e Django REST Framework oferecem integrações maduras. O ganho do Kotlin com Spring é combinar expressividade da linguagem, ecossistema enterprise e segurança integrada sem sair da JVM.\nConclusão Spring Security com Kotlin não precisa ser assustador. Comece com um resource server OAuth2 simples, proteja rotas com scopes claros, deixe regras de domínio dentro das services, teste os cenários de acesso e trate logs como parte da segurança. Essa base resolve a maior parte das APIs backend que aparecem em produtos reais e em vagas Kotlin no Brasil.\nO ponto mais importante é evitar atalhos invisíveis. Segurança não é apenas dependência no build.gradle.kts; é contrato, modelagem, teste, observabilidade e operação. Quando esses elementos trabalham juntos, Kotlin e Spring Boot formam uma stack forte para construir APIs que evoluem sem expor usuários, dados ou o próprio time a riscos desnecessários.\n","permalink":"https://kotlin.dev.br/blog/spring-security-kotlin-jwt-oauth2-2026/","summary":"\u003cp\u003eSegurança em backend Kotlin raramente começa como o tema mais empolgante do projeto, mas costuma ser uma das primeiras áreas cobradas quando a aplicação sai do ambiente local. Login, autorização por papel, tokens JWT, integração com provedor OAuth2, proteção de endpoints administrativos, testes de acesso e logs sem dados sensíveis aparecem em APIs reais, entrevistas e vagas backend no Brasil.\u003c/p\u003e\n\u003cp\u003ePara quem já trabalha com \u003ca href=\"/blog/kotlin-spring-boot/\"\u003eKotlin e Spring Boot\u003c/a\u003e, o caminho mais comum é usar \u003cstrong\u003eSpring Security\u003c/strong\u003e. Ele é maduro, integra bem com o ecossistema JVM e funciona tanto para APIs REST simples quanto para sistemas corporativos conectados a Keycloak, Auth0, Cognito, Microsoft Entra ID ou outro provedor OpenID Connect. A dificuldade não é instalar a dependência. A dificuldade é configurar apenas o necessário, sem transformar a aplicação em um labirinto de filtros, annotations e exceções difíceis de debugar.\u003c/p\u003e","title":"Spring Security com Kotlin: JWT e OAuth2 em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA CI\u0026T busca uma pessoa Desenvolvedora iOS Pleno para atuação remota no Brasil.\nRequisitosExperiência com desenvolvimento iOS usando Swift.Conhecimento de Auto Layout.Vivência com padrões e arquiteturas como VIP, MVC, MVVM e Clean Architecture.Conhecimento de Kotlin.Prática com TDD, SOLID e testes automatizados.Experiência em times ágeis usando Scrum.Modelo de trabalhoVaga remota para profissionais no Brasil, com senioridade pleno.\n","permalink":"https://kotlin.dev.br/vagas/dy1579254yp6rst8-ci-t-desenvolvedor-a-ios-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T busca uma pessoa Desenvolvedora iOS Pleno para atuação remota no Brasil.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com desenvolvimento iOS usando \u003cstrong\u003eSwift\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento de \u003cstrong\u003eAuto Layout\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com padrões e arquiteturas como \u003cstrong\u003eVIP\u003c/strong\u003e, \u003cstrong\u003eMVC\u003c/strong\u003e, \u003cstrong\u003eMVVM\u003c/strong\u003e e \u003cstrong\u003eClean Architecture\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento de \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003ePrática com \u003cstrong\u003eTDD\u003c/strong\u003e, \u003cstrong\u003eSOLID\u003c/strong\u003e e testes automatizados.\u003c/li\u003e\u003cli\u003eExperiência em times ágeis usando \u003cstrong\u003eScrum\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais no Brasil, com senioridade pleno.\u003c/p\u003e","title":"Desenvolvedor(a) iOS Pleno"},{"content":"Sobre a vagaA Playlist busca uma pessoa Engenheira de Software Sênior para atuar na área de Setup e Delivery, em modelo remoto no Brasil.\nTecnologias mencionadasKotlinJavaC#PythonReactRubySQLNew Relic e KibanaSenioridadeNível sênior.\n","permalink":"https://kotlin.dev.br/vagas/f07xmqrz2h33ujcl-playlist-engenheiro-a-de-software-senior-setup-e-delivery/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Playlist busca uma pessoa Engenheira de Software Sênior para atuar na área de Setup e Delivery, em modelo remoto no Brasil.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eC#\u003c/li\u003e\u003cli\u003ePython\u003c/li\u003e\u003cli\u003eReact\u003c/li\u003e\u003cli\u003eRuby\u003c/li\u003e\u003cli\u003eSQL\u003c/li\u003e\u003cli\u003eNew Relic e Kibana\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade\u003c/h3\u003e\u003cp\u003eNível sênior.\u003c/p\u003e","title":"Engenheiro(a) de Software Sênior - Setup e Delivery"},{"content":"Sobre a vagaA CI\u0026T está contratando um Developer Android Mid-Level/Senior para atuar em projetos desafiadores com foco em desenvolvimento de aplicações mobile de alta qualidade.\nResponsabilidadesDesenvolver e manter aplicações Android utilizando Kotlin e JavaImplementar arquitetura limpa seguindo padrões de design reconhecidosEscrever testes automatizados com Mockk e RoboelectricColaborar com times multidisciplinares em ambiente remotoRevisar código e contribuir para melhorias contínuas da base de códigoRequisitosExperiência sólida em desenvolvimento Android (Kotlin e/ou Java)Conhecimento de MVVM e padrões arquiteturaisExperiência com testes unitários e instrumentadosFamiliaridade com ViewBinding e modernização de layouts XMLCompreensão de Clean Code e Design PatternsConhecimento de build tools como MavenDiferenciaisExperiência com Jetpack ComposeContribuições em projetos open sourceExperiência com integração contínua e deploy automatizado ","permalink":"https://kotlin.dev.br/vagas/dqw5eh34gc8iuogj-ci-t-mid-level-senior-developer-android-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T está contratando um Developer Android Mid-Level/Senior para atuar em projetos desafiadores com foco em desenvolvimento de aplicações mobile de alta qualidade.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android utilizando Kotlin e Java\u003c/li\u003e\u003cli\u003eImplementar arquitetura limpa seguindo padrões de design reconhecidos\u003c/li\u003e\u003cli\u003eEscrever testes automatizados com Mockk e Roboelectric\u003c/li\u003e\u003cli\u003eColaborar com times multidisciplinares em ambiente remoto\u003c/li\u003e\u003cli\u003eRevisar código e contribuir para melhorias contínuas da base de código\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sólida em desenvolvimento Android (Kotlin e/ou Java)\u003c/li\u003e\u003cli\u003eConhecimento de MVVM e padrões arquiteturais\u003c/li\u003e\u003cli\u003eExperiência com testes unitários e instrumentados\u003c/li\u003e\u003cli\u003eFamiliaridade com ViewBinding e modernização de layouts XML\u003c/li\u003e\u003cli\u003eCompreensão de Clean Code e Design Patterns\u003c/li\u003e\u003cli\u003eConhecimento de build tools como Maven\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Jetpack Compose\u003c/li\u003e\u003cli\u003eContribuições em projetos open source\u003c/li\u003e\u003cli\u003eExperiência com integração contínua e deploy automatizado\u003c/li\u003e\u003c/ul\u003e","title":"Mid-Level/Senior Developer Android (Kotlin)"},{"content":"Sobre a vagaProcuramos um Principal Mobile Architect experiente para liderar a estratégia e arquitetura de aplicações mobile em nossa organização. Você trabalhará com tecnologias modernas como Kotlin e Swift, definindo padrões e melhores práticas para times de desenvolvimento.\nResponsabilidadesDefinir e evoluir a arquitetura mobile da organizaçãoLiderar iniciativas de modernização e escalabilidadeMentorear times de desenvolvimento mobileEstabelecer padrões de código, segurança e performanceColaborar com liderança técnica em decisões estratégicasRequisitosExperiência sênior em arquitetura mobile (5+ anos)Profundo conhecimento em Kotlin e/ou SwiftExperiência em Design Driven Development (DDD)Histórico de liderança técnica e mentoriaConhecimento de CI/CD e DevOpsDiferenciaisExperiência com FinOps e otimização de custos em cloudContribuições a projetos open sourceExperiência em arquitetura de aplicações iOS e Android em larga escala ","permalink":"https://kotlin.dev.br/vagas/xad1jxcap8vh5y55-ci-t-principal-mobile-architect/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eProcuramos um Principal Mobile Architect experiente para liderar a estratégia e arquitetura de aplicações mobile em nossa organização. Você trabalhará com tecnologias modernas como Kotlin e Swift, definindo padrões e melhores práticas para times de desenvolvimento.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDefinir e evoluir a arquitetura mobile da organização\u003c/li\u003e\u003cli\u003eLiderar iniciativas de modernização e escalabilidade\u003c/li\u003e\u003cli\u003eMentorear times de desenvolvimento mobile\u003c/li\u003e\u003cli\u003eEstabelecer padrões de código, segurança e performance\u003c/li\u003e\u003cli\u003eColaborar com liderança técnica em decisões estratégicas\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em arquitetura mobile (5+ anos)\u003c/li\u003e\u003cli\u003eProfundo conhecimento em Kotlin e/ou Swift\u003c/li\u003e\u003cli\u003eExperiência em Design Driven Development (DDD)\u003c/li\u003e\u003cli\u003eHistórico de liderança técnica e mentoria\u003c/li\u003e\u003cli\u003eConhecimento de CI/CD e DevOps\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com FinOps e otimização de custos em cloud\u003c/li\u003e\u003cli\u003eContribuições a projetos open source\u003c/li\u003e\u003cli\u003eExperiência em arquitetura de aplicações iOS e Android em larga escala\u003c/li\u003e\u003c/ul\u003e","title":"Principal Mobile Architect"},{"content":"Sobre a vagaProcuramos um Senior Backend Software Engineer para atuar na plataforma CARE de Engagement \u0026 Platform da Wellhub, em regime remoto.\nResponsabilidadesDesenvolver e manter serviços backend escaláveisTrabalhar com arquitetura de microsserviços e processamento de dados em tempo realOtimizar pipelines de dados e integraçõesContribuir para decisões de arquitetura e design de sistemasRequisitosExperiência comprovada como Backend Engineer em nível sêniorProficiência em Kotlin, Python, Java ou GoConhecimento em arquitetura de nuvem (AWS)Experiência com bancos de dados (PostgreSQL, DynamoDB)Familiaridade com Kafka, SQS e arquitetura de eventosDiferenciaisExperiência com OpenSearch, Airflow, Grafana e PrometheusConhecimento em observabilidade (OpenTelemetry)Familiaridade com infraestrutura como código ","permalink":"https://kotlin.dev.br/vagas/whckna1vchrp56s0-wellhub-senior-backend-software-engineer-care-engagement-platfo/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eProcuramos um Senior Backend Software Engineer para atuar na plataforma CARE de Engagement \u0026 Platform da Wellhub, em regime remoto.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend escaláveis\u003c/li\u003e\u003cli\u003eTrabalhar com arquitetura de microsserviços e processamento de dados em tempo real\u003c/li\u003e\u003cli\u003eOtimizar pipelines de dados e integrações\u003c/li\u003e\u003cli\u003eContribuir para decisões de arquitetura e design de sistemas\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência comprovada como Backend Engineer em nível sênior\u003c/li\u003e\u003cli\u003eProficiência em Kotlin, Python, Java ou Go\u003c/li\u003e\u003cli\u003eConhecimento em arquitetura de nuvem (AWS)\u003c/li\u003e\u003cli\u003eExperiência com bancos de dados (PostgreSQL, DynamoDB)\u003c/li\u003e\u003cli\u003eFamiliaridade com Kafka, SQS e arquitetura de eventos\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com OpenSearch, Airflow, Grafana e Prometheus\u003c/li\u003e\u003cli\u003eConhecimento em observabilidade (OpenTelemetry)\u003c/li\u003e\u003cli\u003eFamiliaridade com infraestrutura como código\u003c/li\u003e\u003c/ul\u003e","title":"Senior Backend Software Engineer – CARE Engagement \u0026 Platform"},{"content":"Sobre a vagaA Playlist está recrutando um Senior Software Engineer para atuar remotamente no Brasil. Você trabalhará com uma stack diversificada incluindo Kotlin, Java, C#, Python e React, contribuindo para sistemas críticos da plataforma.\nRequisitosExperiência sênior em desenvolvimento de softwareProficiência em Kotlin, Java, C# ou linguagens similaresConhecimento em SQL e banco de dadosExperiência com observabilidade e monitoramento (New Relic, Kibana)Capacidade de trabalhar remotamente de forma autônomaDiferenciaisExperiência com React ou tecnologias frontendConhecimento em arquitetura de sistemas distribuídosContribuições open source ","permalink":"https://kotlin.dev.br/vagas/w0046qqlqm0bl5jj-playlist-senior-software-engineer/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Playlist está recrutando um Senior Software Engineer para atuar remotamente no Brasil. Você trabalhará com uma stack diversificada incluindo Kotlin, Java, C#, Python e React, contribuindo para sistemas críticos da plataforma.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento de software\u003c/li\u003e\u003cli\u003eProficiência em Kotlin, Java, C# ou linguagens similares\u003c/li\u003e\u003cli\u003eConhecimento em SQL e banco de dados\u003c/li\u003e\u003cli\u003eExperiência com observabilidade e monitoramento (New Relic, Kibana)\u003c/li\u003e\u003cli\u003eCapacidade de trabalhar remotamente de forma autônoma\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com React ou tecnologias frontend\u003c/li\u003e\u003cli\u003eConhecimento em arquitetura de sistemas distribuídos\u003c/li\u003e\u003cli\u003eContribuições open source\u003c/li\u003e\u003c/ul\u003e","title":"Senior Software Engineer"},{"content":"Testes Android com Kotlin deixam de ser um assunto opcional quando o app começa a ter login, estado offline, sincronização em segundo plano, pagamento, feature flags ou telas em Jetpack Compose. Sem uma estratégia mínima, cada refatoração de ViewModel vira medo, cada mudança de layout pode quebrar um fluxo importante e cada bug de sincronização volta em produção depois de parecer resolvido no emulador.\nO objetivo deste guia é montar uma estratégia prática para 2026, sem transformar testes em um projeto paralelo. A ideia é combinar testes unitários rápidos para regras e estado, testes de integração para persistência e sincronização, testes de UI em Compose quando a tela é o contrato, e poucos testes end-to-end com Maestro para jornadas críticas.\nSe você ainda está construindo a base do app, leia também o roadmap de desenvolvedor Android, o guia de testes em Kotlin e a trilha de Android offline-first com Kotlin. Eles ajudam a decidir o que deve estar em ViewModel, repository, Room, WorkManager e UI.\nA pirâmide de testes para Android Kotlin Um app Android moderno costuma misturar três tipos de código: lógica pura em Kotlin, integração com bibliotecas Android e interface. Cada tipo pede um teste diferente.\nTestes unitários JVM: validam use cases, validators, mappers, reducers, ViewModels, repositories fake e regras de domínio. Testes de coroutines e Flow: verificam estados assíncronos, cancelamento, retry, debounce, sincronização e emissão de eventos. Testes locais com Robolectric: ajudam quando uma parte usa recursos do Android framework, mas ainda pode rodar fora do emulador. Testes instrumentados: rodam em device ou emulador e validam Room real, Compose UI, permissões, navegação e componentes Android. Testes end-to-end: cobrem jornadas de usuário com Maestro, Espresso ou outra ferramenta de automação. A regra prática é simples: deixe a maior parte do comportamento fora da UI e teste na JVM. Use emulador apenas quando o comportamento realmente depende do Android. Isso mantém a suíte rápida e reduz flakiness.\nDependências base no Gradle Em um projeto Android com Gradle Kotlin DSL, uma base comum fica parecida com esta:\ndependencies { testImplementation(\u0026#34;junit:junit:4.13.2\u0026#34;) testImplementation(\u0026#34;io.mockk:mockk:1.13.12\u0026#34;) testImplementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1\u0026#34;) testImplementation(\u0026#34;app.cash.turbine:turbine:1.1.0\u0026#34;) androidTestImplementation(\u0026#34;androidx.test.ext:junit:1.1.5\u0026#34;) androidTestImplementation(\u0026#34;androidx.test.espresso:espresso-core:3.5.1\u0026#34;) androidTestImplementation(\u0026#34;androidx.compose.ui:ui-test-junit4\u0026#34;) debugImplementation(\u0026#34;androidx.compose.ui:ui-test-manifest\u0026#34;) } Use versões compatíveis com seu Android Gradle Plugin, Kotlin e Compose BOM. O importante é separar o que roda em test do que roda em androidTest. Misturar tudo no emulador deixa o feedback lento demais para pull request.\nTestando ViewModel com StateFlow ViewModel costuma ser o melhor ponto para começar. Ela coordena estado de tela, chama casos de uso, transforma erro em mensagem e decide quando mostrar loading. Se esse código estiver testado, boa parte da UI vira uma função simples do estado.\n@Test fun `deve emitir sucesso ao carregar tarefas`() = runTest { val repository = mockk\u0026lt;TarefaRepository\u0026gt;() coEvery { repository.listar() } returns listOf(Tarefa(\u0026#34;Estudar Compose\u0026#34;)) val viewModel = TarefasViewModel(repository) viewModel.estado.test { assertEquals(TarefasState.Loading, awaitItem()) viewModel.carregar() assertEquals(TarefasState.Sucesso(listOf(\u0026#34;Estudar Compose\u0026#34;)), awaitItem()) cancelAndIgnoreRemainingEvents() } } Para esse tipo de teste, evite delay real e Thread.sleep. Use runTest, dispatchers controlados e Turbine para ler emissões de Flow ou StateFlow. Isso deixa o teste determinístico e rápido.\nTestando Compose sem acoplar ao texto Em Compose, prefira testar contratos estáveis. Texto visível muda com copy, tradução e experimento. Tags semânticas costumam ser mais resistentes:\n@Composable fun LoginScreen(state: LoginState, onEntrar: () -\u0026gt; Unit) { Column { TextField( value = state.email, onValueChange = {}, modifier = Modifier.testTag(\u0026#34;login_email\u0026#34;), ) Button( onClick = onEntrar, modifier = Modifier.testTag(\u0026#34;login_submit\u0026#34;), ) { Text(\u0026#34;Entrar\u0026#34;) } } } O teste instrumentado fica direto:\n@Test fun deveEnviarLoginAoTocarNoBotao() { var enviado = false composeRule.setContent { LoginScreen(LoginState(email = \u0026#34;ana@example.com\u0026#34;), onEntrar = { enviado = true }) } composeRule.onNodeWithTag(\u0026#34;login_submit\u0026#34;).performClick() assertTrue(enviado) } Não teste cada detalhe visual com teste funcional. Para regressão visual, avalie screenshot testing. Para regra de negócio, volte para ViewModel ou use case. Teste de UI deve provar interação, acessibilidade básica, estados vazios, erro e navegação crítica.\nRoom, DataStore e WorkManager Persistência e trabalho em segundo plano merecem cuidado porque bugs aparecem depois de uso real: app fechado, rede instável, conflito de dados, retry duplicado e migração de schema.\nPara Room, teste DAOs e migrations com banco instrumentado quando o comportamento depende de SQLite real. Para DataStore, isole diretórios temporários e valide as emissões com Flow. Para WorkManager, mantenha a regra pesada em um use case testável e deixe o worker como coordenador fino.\nUm bom recorte é:\nteste unitário para decidir quais registros precisam sincronizar; teste de repository para garantir que o estado local muda corretamente; teste instrumentado curto para provar que o worker agenda e chama o caso de uso; teste E2E apenas para uma jornada offline-first importante. Isso evita um worker gigante e difícil de testar.\nQuando usar Espresso e quando usar Maestro Espresso ainda funciona bem para interações Android nativas e integrações dentro do próprio app. Em Compose, a API compose-ui-test costuma ser mais natural. Maestro entra melhor quando você quer validar uma jornada de produto como uma pessoa usuária faria: abrir app, fazer login, navegar, criar item, fechar, reabrir e confirmar persistência.\nUm fluxo Maestro simples pode ser:\nappId: br.dev.kotlin.exemplo --- - launchApp - tapOn: \u0026#34;Entrar\u0026#34; - inputText: \u0026#34;ana@example.com\u0026#34; - tapOn: \u0026#34;Continuar\u0026#34; - assertVisible: \u0026#34;Minhas tarefas\u0026#34; Use Maestro para poucos fluxos de alto valor. Se você automatizar vinte jornadas longas, a manutenção cresce rápido. Comece com login, onboarding, criação de item principal, fluxo offline e deep link crítico. Para desenhar esse contrato antes do teste, veja o guia de App Links e deep links no Android com Kotlin.\nCI/CD sem deixar a suíte lenta Uma pipeline saudável separa feedback rápido de validação pesada:\n./gradlew testDebugUnitTest em todo pull request. ./gradlew ktlintCheck detekt junto dos testes unitários. ./gradlew connectedDebugAndroidTest em PRs que mexem em UI, Room, navegação ou integração Android. Maestro em branch principal, release candidate ou PRs de fluxos críticos. Relatórios de teste e screenshots como artefatos do CI para facilitar debug. O guia de CI/CD para Kotlin mostra como organizar a automação. O ponto mais importante é não mascarar falhas essenciais com continue-on-error. Teste instável precisa ser corrigido, reduzido ou removido. Se ele falha aleatoriamente e ninguém investiga, ele deixa de proteger o produto.\nChecklist para uma suíte Android sustentável ViewModels e use cases rodam na JVM com runTest. Estados de tela são modelados de forma explícita, com loading, sucesso, vazio e erro. Composables importantes usam testTag ou semântica acessível estável. Room, DataStore e WorkManager têm ao menos testes dos caminhos críticos. Fluxos E2E cobrem poucas jornadas de alto impacto, não todos os botões. CI separa teste rápido de teste instrumentado e mantém logs legíveis. Bugs corrigidos viram teste quando o risco de regressão é real. Próximos passos Se seu app Android ainda não tem testes, comece pequeno. Escolha uma ViewModel que muda com frequência, escreva testes para sucesso e erro, depois adicione um teste de Compose para a tela mais crítica. Em seguida, cubra persistência local com Room ou DataStore e coloque a suíte básica no CI.\nCom o tempo, você pode evoluir para screenshot testing, device farms, testes de acessibilidade e automações Maestro mais completas. Mas a base continua a mesma: regra fora da UI, estado observável, testes rápidos primeiro e emulador apenas onde ele realmente compra confiança.\nPara avançar na trilha Android, combine este guia com MVVM em Kotlin, Room Database, DataStore Preferences, WorkManager e Android offline-first. Essa sequência mostra ao mercado que você sabe entregar app Kotlin com qualidade, não apenas montar telas.\n","permalink":"https://kotlin.dev.br/guias/testes-android-compose-maestro/","summary":"\u003cp\u003eTestes Android com Kotlin deixam de ser um assunto opcional quando o app começa a ter login, estado offline, sincronização em segundo plano, pagamento, feature flags ou telas em \u003ca href=\"/guias/guia-jetpack-compose/\"\u003eJetpack Compose\u003c/a\u003e. Sem uma estratégia mínima, cada refatoração de ViewModel vira medo, cada mudança de layout pode quebrar um fluxo importante e cada bug de sincronização volta em produção depois de parecer resolvido no emulador.\u003c/p\u003e\n\u003cp\u003eO objetivo deste guia é montar uma estratégia prática para 2026, sem transformar testes em um projeto paralelo. A ideia é combinar testes unitários rápidos para regras e estado, testes de integração para persistência e sincronização, testes de UI em Compose quando a tela é o contrato, e poucos testes end-to-end com Maestro para jornadas críticas.\u003c/p\u003e","title":"Testes Android com Kotlin: Compose, JUnit e Maestro | Kotlin Brasil"},{"content":"APIs REST resolvem muito bem consultas, cadastros e integrações previsíveis. Mas alguns produtos precisam de uma conversa aberta entre cliente e servidor: chat, painel administrativo com eventos ao vivo, sala de votação, dashboard operacional, colaboração em documento, rastreamento de entrega, jogo simples ou notificação que não pode esperar o próximo refresh. Para esses cenários, WebSockets com Ktor e Kotlin são uma alternativa direta, idiomática e alinhada com coroutines.\nEste tutorial mostra como criar um endpoint WebSocket no Ktor, receber mensagens, transmitir eventos para usuários conectados e preparar o caminho para produção. Se você ainda está montando a base do backend, comece pelo tutorial de Ktor para APIs REST e pelo guia completo de Ktor para backend. Aqui vamos focar na parte em tempo real.\nQuando WebSocket faz sentido WebSocket mantém uma conexão aberta e bidirecional. O cliente pode enviar mensagens a qualquer momento, e o servidor também pode empurrar eventos sem esperar uma nova requisição HTTP. Isso é diferente de polling, onde o cliente pergunta repetidamente “tem novidade?”, e diferente de Server-Sent Events, que costuma ser mais simples quando o fluxo é apenas servidor para cliente.\nUse WebSocket quando você precisa de:\ncomunicação bidirecional com baixa latência; eventos frequentes e pequenos; presença de usuários conectados; salas, canais ou tópicos compartilhados; confirmação rápida de mensagens; experiência interativa em navegador, Android ou desktop. Evite WebSocket quando uma requisição REST resolve bem o problema. Manter conexões abertas tem custo operacional: timeout, autenticação, reconexão, balanceamento, observabilidade e limites por usuário precisam ser pensados desde cedo.\nDependências do projeto Em um projeto Ktor com Gradle Kotlin DSL, adicione o plugin de WebSockets e serialização JSON:\nplugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.0.0\u0026#34; id(\u0026#34;io.ktor.plugin\u0026#34;) version \u0026#34;2.3.12\u0026#34; kotlin(\u0026#34;plugin.serialization\u0026#34;) version \u0026#34;2.0.0\u0026#34; } dependencies { implementation(\u0026#34;io.ktor:ktor-server-core-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-netty-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-websockets-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-serialization-kotlinx-json-jvm\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1\u0026#34;) } As versões acima são didáticas. Em projeto real, confira as versões atuais no catálogo do time e evite misturar versões incompatíveis de Kotlin, Ktor e kotlinx.serialization. Se você usa Version Catalog, veja também o artigo sobre Gradle Version Catalog em Kotlin.\nInstalando o plugin WebSockets No Ktor, WebSocket é um plugin instalado na aplicação. A configuração mínima define ping periódico e timeout para detectar conexões mortas:\nimport io.ktor.server.application.* import io.ktor.server.plugins.websocket.* import kotlin.time.Duration.Companion.seconds fun Application.module() { install(WebSockets) { pingPeriod = 20.seconds timeout = 20.seconds maxFrameSize = Long.MAX_VALUE masking = false } configurarRotasTempoReal() } pingPeriod ajuda o servidor a perceber quando o cliente sumiu sem fechar a conexão corretamente, algo comum em redes móveis. timeout define quanto tempo esperar por resposta. Em produção, não deixe maxFrameSize infinito sem necessidade: limite o tamanho da mensagem para evitar abuso e consumo de memória.\nCriando um endpoint de chat O exemplo abaixo cria uma sala simples. Cada conexão recebe mensagens de texto e retransmite para todas as outras sessões conectadas. É um ponto de partida para entender o fluxo, não uma arquitetura final de produto.\nimport io.ktor.server.application.* import io.ktor.server.routing.* import io.ktor.server.websocket.* import io.ktor.websocket.* import java.util.Collections private val sessoes = Collections.synchronizedSet(mutableSetOf\u0026lt;DefaultWebSocketServerSession\u0026gt;()) fun Application.configurarRotasTempoReal() { routing { webSocket(\u0026#34;/ws/chat\u0026#34;) { sessoes += this try { send(\u0026#34;Conectado ao chat Kotlin Brasil\u0026#34;) for (frame in incoming) { if (frame is Frame.Text) { val texto = frame.readText().trim() if (texto.isNotBlank()) { transmitir(\u0026#34;usuario: $texto\u0026#34;) } } } } finally { sessoes -= this } } } } private suspend fun transmitir(mensagem: String) { sessoes.toList().forEach { sessao -\u0026gt; sessao.send(mensagem) } } A ideia principal é que incoming funciona como um fluxo de frames recebidos. Dentro do loop, você trata texto, binário, ping, pong ou close conforme o protocolo do seu produto. Para chat e notificações, texto com JSON costuma ser suficiente.\nUse mensagens tipadas com kotlinx.serialization Em vez de transmitir strings soltas, modele contrato. Isso facilita evolução, validação e testes:\nimport kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json @Serializable sealed interface EventoChat { @Serializable @SerialName(\u0026#34;mensagem\u0026#34;) data class Mensagem( val usuario: String, val texto: String, val enviadaEm: Long, ) : EventoChat @Serializable @SerialName(\u0026#34;presenca\u0026#34;) data class Presenca( val usuario: String, val online: Boolean, ) : EventoChat } private val json = Json { ignoreUnknownKeys = true classDiscriminator = \u0026#34;tipo\u0026#34; } Com esse modelo, o cliente sabe se recebeu mensagem, presença ou outro evento futuro. Também fica mais fácil integrar com Android, Compose Multiplatform ou frontend web sem depender de parsing frágil.\nAutenticação e salas Não confie em usuario vindo do corpo da mensagem. Em produção, autentique antes de aceitar a conexão. Uma abordagem comum é enviar um token curto no header Authorization ou na query string apenas se o ambiente não permitir headers customizados. O servidor valida o token, identifica o usuário e decide quais salas ele pode acessar.\nUm desenho mais realista separa responsabilidades:\nConnectionRegistry guarda conexões por usuário e sala; ChatService valida comandos e aplica regras de negócio; MessageRepository persiste histórico quando necessário; EventPublisher publica eventos para outras instâncias do serviço. Essa separação evita colocar regra de negócio diretamente dentro do bloco webSocket. O bloco deve orquestrar conexão, leitura, escrita e fechamento; a decisão de domínio deve ficar em serviços testáveis.\nCuidado com múltiplas instâncias O exemplo com sessoes em memória funciona em uma única instância. Se você roda o Ktor em Kubernetes, Cloud Run, VPS com balanceador ou qualquer ambiente com réplicas, um usuário pode estar conectado na instância A enquanto outro está na instância B. Nesse caso, retransmitir apenas para a memória local não basta.\nPara escalar, use um barramento externo: Redis Pub/Sub, Kafka, RabbitMQ, NATS ou outro sistema de mensageria. O endpoint WebSocket recebe a mensagem, valida, publica no barramento e cada instância repassa para suas conexões locais. O artigo sobre Kotlin com Kafka e RabbitMQ aprofunda esse tipo de arquitetura. Para comparar contratos de serviço em outro ecossistema do cluster, o guia de gRPC e microserviços em Rust mostra uma alternativa natural quando a comunicação entre backends precisa de schema forte e baixa latência.\nTambém revise afinidade de sessão. Alguns balanceadores permitem sticky sessions, mas isso não substitui um barramento quando o produto precisa entregar eventos entre usuários conectados em réplicas diferentes.\nTestes e observabilidade Teste WebSocket em três camadas. Primeiro, teste serviços puros: validação de comando, permissões, formatação de evento e persistência. Depois, teste o endpoint Ktor com cliente WebSocket de teste. Por fim, rode um teste manual ou automatizado em ambiente de staging para cobrir proxy, TLS e timeout real.\nMétricas úteis incluem:\nconexões abertas por instância; mensagens recebidas e enviadas por sala; erros de parsing e autenticação; tempo médio de conexão; desconexões por timeout; tamanho médio de payload. Logs devem incluir identificador de usuário, sala e correlation id, mas nunca token, senha ou dados sensíveis. Para aprofundar essa disciplina, veja observabilidade em Kotlin e o guia de Ktor Client resiliente, que discute timeout, fallback e rastreabilidade em integrações HTTP.\nChecklist antes de produção Antes de publicar um WebSocket Ktor em produção, revise:\nAutenticação obrigatória e autorização por sala ou recurso. Limite de tamanho de mensagem. Ping, timeout e política de reconexão documentados para o cliente. Validação de JSON e rejeição de tipo desconhecido. Backpressure ou limite de fila por conexão lenta. Métricas de conexão, erro e throughput. Estratégia para múltiplas instâncias. Teste com proxy/TLS igual ao ambiente real. Esse checklist evita a armadilha de tratar WebSocket como “apenas uma rota diferente”. Na prática, ele muda o ciclo de vida da conexão e cria uma superfície operacional nova.\nConclusão Ktor torna WebSockets em Kotlin bastante acessíveis: instalar o plugin, criar uma rota webSocket, ler frames e enviar respostas é simples. O valor real aparece quando você combina essa simplicidade com contratos tipados, coroutines, autenticação, observabilidade e uma estratégia clara para escalar além de uma única instância.\nSe seu projeto precisa de chat, presença, notificações ou eventos em tempo real, comece pequeno com uma sala simples, teste bem o protocolo e evolua para mensageria externa quando houver múltiplas réplicas. Esse caminho mantém o código Kotlin idiomático sem ignorar as exigências de produção.\n","permalink":"https://kotlin.dev.br/tutoriais/ktor-websockets-kotlin/","summary":"\u003cp\u003eAPIs REST resolvem muito bem consultas, cadastros e integrações previsíveis. Mas alguns produtos precisam de uma conversa aberta entre cliente e servidor: chat, painel administrativo com eventos ao vivo, sala de votação, dashboard operacional, colaboração em documento, rastreamento de entrega, jogo simples ou notificação que não pode esperar o próximo refresh. Para esses cenários, \u003cstrong\u003eWebSockets com Ktor e Kotlin\u003c/strong\u003e são uma alternativa direta, idiomática e alinhada com coroutines.\u003c/p\u003e\n\u003cp\u003eEste tutorial mostra como criar um endpoint WebSocket no Ktor, receber mensagens, transmitir eventos para usuários conectados e preparar o caminho para produção. Se você ainda está montando a base do backend, comece pelo \u003ca href=\"/tutoriais/kotlin-ktor-tutorial/\"\u003etutorial de Ktor para APIs REST\u003c/a\u003e e pelo \u003ca href=\"/guias/guia-kotlin-backend-ktor/\"\u003eguia completo de Ktor para backend\u003c/a\u003e. Aqui vamos focar na parte em tempo real.\u003c/p\u003e","title":"WebSockets com Ktor e Kotlin: Chat em Tempo Real | Kotlin Brasil"},{"content":"Listas grandes parecem simples até o app começar a travar, repetir itens, perder posição de rolagem ou baixar milhares de registros de uma vez. Em apps Android reais, feeds, catálogos, históricos, chats, pedidos, notificações, resultados de busca e telas administrativas raramente cabem em uma única resposta HTTP. É nesse ponto que Paging 3 com Kotlin e Jetpack Compose deixa de ser detalhe de performance e vira parte importante da arquitetura.\nO Paging 3 é a biblioteca oficial do Android Jetpack para carregar dados em páginas, combinar fontes locais e remotas, expor fluxo reativo com Flow\u0026lt;PagingData\u0026lt;T\u0026gt;\u0026gt; e integrar com listas Compose por meio de LazyPagingItems. Quando usado bem, ele reduz consumo de memória, melhora tempo de primeira renderização e cria uma experiência mais estável em conexões brasileiras comuns: 4G instável, Wi-Fi público, rede corporativa com proxy e dispositivos intermediários.\nEste guia mostra quando usar Paging 3, como criar um PagingSource, como integrar com Jetpack Compose, quando usar RemoteMediator com Room, como tratar LoadState, quais erros evitar e como testar a camada de paginação. Se você já estudou Flow em Kotlin, Room Database, Android offline-first e WorkManager, o Paging 3 completa uma peça essencial para apps Android modernos.\nQuando usar Paging 3? Use Paging 3 quando a tela trabalha com uma coleção potencialmente grande ou dinâmica. Alguns exemplos comuns:\nfeed de posts, produtos, notícias ou transações; busca com muitos resultados; histórico de pedidos, corridas, pagamentos ou mensagens; catálogo offline sincronizado em partes; lista de usuários, clientes, tarefas ou chamados; timeline ordenada por data, popularidade ou relevância. Não use Paging 3 para listas pequenas e estáticas. Se a tela sempre exibe 10 categorias fixas, uma lista comum é mais simples. Também não vale complicar um formulário com paginação apenas porque a API suporta page e limit. A pergunta prática é: a lista pode crescer a ponto de afetar memória, rede, tempo de resposta ou experiência de rolagem? Se sim, Paging 3 merece entrar na arquitetura.\nDependências básicas Em um app Android com Gradle Kotlin DSL, você normalmente adiciona as integrações de runtime e Compose:\ndependencies { implementation(\u0026#34;androidx.paging:paging-runtime-ktx:3.3.6\u0026#34;) implementation(\u0026#34;androidx.paging:paging-compose:3.3.6\u0026#34;) } Confira a versão mais recente compatível com o seu projeto, especialmente se você usa Kotlin, Compose Compiler e Android Gradle Plugin em versões novas. Em projetos com Room, a integração costuma ficar ainda mais simples porque DAOs podem retornar PagingSource diretamente.\nO modelo mental do Paging 3 O Paging 3 separa responsabilidades em três pontos principais:\nPagingSource: sabe carregar uma página a partir de uma chave; Pager: configura tamanho da página, placeholders e fonte de dados; PagingData: fluxo de dados paginados consumido pela UI. Em um caso simples, o repository expõe um Flow\u0026lt;PagingData\u0026lt;Item\u0026gt;\u0026gt;. O ViewModel aplica cache no viewModelScope. A tela Compose coleta esse fluxo com collectAsLazyPagingItems() e renderiza usando LazyColumn.\nEssa separação combina bem com MVVM em Kotlin porque a UI não precisa conhecer detalhes de página, offset, cursor, retry HTTP ou banco local. Ela observa um estado paginado e reage a carregamento, erro e conteúdo vazio.\nPagingSource com API remota Um PagingSource recebe uma chave e devolve uma página. A chave pode ser número da página, offset, timestamp, cursor ou token enviado pela API. Para APIs tradicionais com page, o código fica assim:\nclass ProdutosPagingSource( private val api: ProdutosApi, private val termo: String, ) : PagingSource\u0026lt;Int, Produto\u0026gt;() { override suspend fun load(params: LoadParams\u0026lt;Int\u0026gt;): LoadResult\u0026lt;Int, Produto\u0026gt; { val pagina = params.key ?: 1 return try { val resposta = api.buscarProdutos( query = termo, page = pagina, pageSize = params.loadSize, ) LoadResult.Page( data = resposta.items, prevKey = if (pagina == 1) null else pagina - 1, nextKey = if (resposta.items.isEmpty()) null else pagina + 1, ) } catch (erro: IOException) { LoadResult.Error(erro) } catch (erro: HttpException) { LoadResult.Error(erro) } } override fun getRefreshKey(state: PagingState\u0026lt;Int, Produto\u0026gt;): Int? { return state.anchorPosition?.let { anchor -\u0026gt; val paginaMaisProxima = state.closestPageToPosition(anchor) paginaMaisProxima?.prevKey?.plus(1) ?: paginaMaisProxima?.nextKey?.minus(1) } } } O método getRefreshKey parece burocrático, mas é importante para manter a posição aproximada do usuário quando a lista é atualizada. Sem ele, refreshes podem voltar para o começo da lista de forma irritante.\nRepository e ViewModel O repository monta o Pager e esconde a implementação da UI:\nclass ProdutosRepository( private val api: ProdutosApi, ) { fun buscarProdutos(termo: String): Flow\u0026lt;PagingData\u0026lt;Produto\u0026gt;\u0026gt; { return Pager( config = PagingConfig( pageSize = 20, initialLoadSize = 40, prefetchDistance = 5, enablePlaceholders = false, ), pagingSourceFactory = { ProdutosPagingSource(api = api, termo = termo) }, ).flow } } No ViewModel, use cachedIn(viewModelScope) para evitar recarregamento desnecessário quando a tela recompõe ou quando há múltiplos collectors:\nclass ProdutosViewModel( private val repository: ProdutosRepository, ) : ViewModel() { private val termoBusca = MutableStateFlow(\u0026#34;\u0026#34;) val produtos: Flow\u0026lt;PagingData\u0026lt;Produto\u0026gt;\u0026gt; = termoBusca .debounce(300) .distinctUntilChanged() .flatMapLatest { termo -\u0026gt; repository.buscarProdutos(termo) } .cachedIn(viewModelScope) fun atualizarBusca(novoTermo: String) { termoBusca.value = novoTermo } } Esse padrão é útil para busca porque cada termo cria uma nova fonte de paginação. flatMapLatest cancela a busca anterior quando o usuário digita algo novo, evitando corrida entre respostas antigas e novas.\nConsumindo PagingData no Jetpack Compose No Compose, a integração fica direta:\n@Composable fun ProdutosScreen( viewModel: ProdutosViewModel, ) { val produtos = viewModel.produtos.collectAsLazyPagingItems() LazyColumn { items( count = produtos.itemCount, key = produtos.itemKey { it.id }, ) { index -\u0026gt; val produto = produtos[index] if (produto != null) { ProdutoCard(produto = produto) } else { ProdutoPlaceholder() } } } } Use key estável sempre que possível. Isso ajuda o Compose a preservar estado de itens, animações e posição de rolagem. Se você usa id vindo do backend, prefira esse identificador em vez do índice da lista.\nTratando loading, erro e lista vazia Uma tela paginada precisa diferenciar três estados:\ncarregamento inicial (refresh); carregamento no final da lista (append); erro inicial ou erro ao buscar a próxima página. @Composable fun ProdutosContent(produtos: LazyPagingItems\u0026lt;Produto\u0026gt;) { when (val refresh = produtos.loadState.refresh) { is LoadState.Loading -\u0026gt; LoadingTelaInteira() is LoadState.Error -\u0026gt; ErroTelaInteira( mensagem = refresh.error.message ?: \u0026#34;Não foi possível carregar os produtos.\u0026#34;, onRetry = { produtos.retry() }, ) is LoadState.NotLoading -\u0026gt; { if (produtos.itemCount == 0) { EmptyState(mensagem = \u0026#34;Nenhum produto encontrado.\u0026#34;) } else { ListaProdutos(produtos) } } } } Para append, o ideal é renderizar um item no rodapé:\nif (produtos.loadState.append is LoadState.Loading) { item { LoadingRodape() } } if (produtos.loadState.append is LoadState.Error) { item { BotaoTentarNovamente(onClick = { produtos.retry() }) } } Essa diferença melhora bastante a experiência. Um erro na próxima página não deve apagar os itens já carregados. A lista pode continuar visível, com um retry discreto no rodapé.\nPaging 3 com Room e RemoteMediator Para apps offline-first, o padrão mais robusto é usar Room como fonte local e RemoteMediator para sincronizar rede e banco. A UI lê do banco. O mediator decide quando buscar mais dados e salvar localmente. Isso combina com a arquitetura descrita no guia de Android offline-first com Kotlin.\nO DAO pode retornar PagingSource:\n@Dao interface ProdutoDao { @Query(\u0026#34;SELECT * FROM produtos ORDER BY nome ASC\u0026#34;) fun paginarProdutos(): PagingSource\u0026lt;Int, ProdutoEntity\u0026gt; } O repository usa o banco como fonte principal:\nfun produtosOfflineFirst(): Flow\u0026lt;PagingData\u0026lt;Produto\u0026gt;\u0026gt; { return Pager( config = PagingConfig(pageSize = 30), remoteMediator = ProdutosRemoteMediator(api, database), pagingSourceFactory = { database.produtoDao().paginarProdutos() }, ).flow.map { pagingData -\u0026gt; pagingData.map { entity -\u0026gt; entity.toDomain() } } } Esse desenho evita que a tela dependa diretamente da rede. Se o usuário abre o app sem conexão, os dados locais continuam aparecendo. Quando a rede volta, o mediator atualiza o banco e a lista reflete as mudanças automaticamente.\nTamanho de página, prefetch e placeholders Não existe um tamanho perfeito de página. Comece com algo entre 20 e 50 itens e ajuste medindo tempo de resposta, tamanho do payload e custo de renderização. Páginas muito pequenas aumentam overhead de rede. Páginas grandes demais atrasam o primeiro carregamento e podem causar jank em dispositivos modestos.\nprefetchDistance define quando o Paging começa a buscar a próxima página antes de o usuário chegar ao fim. Um valor baixo economiza rede, mas pode mostrar loading com frequência. Um valor alto deixa a rolagem mais fluida, mas pode baixar dados que o usuário nunca verá.\nenablePlaceholders só faz sentido quando você sabe o tamanho total da lista e quer reservar espaço para itens ainda não carregados. Em muitos feeds e buscas, false é mais previsível.\nErros comuns em projetos Kotlin O primeiro erro é recriar o Pager a cada recomposição. O Pager deve ficar no repository ou no ViewModel, não dentro de um @Composable comum. Compose pode recompor muitas vezes; paginação não deve reiniciar por causa disso.\nO segundo erro é esquecer cachedIn(viewModelScope). Sem cache, mudanças de configuração e novos collectors podem disparar novas cargas desnecessárias.\nO terceiro erro é tratar todo erro como tela cheia. Se o erro acontece no append, preserve a lista e ofereça retry no rodapé.\nO quarto erro é misturar filtros sem invalidar corretamente a fonte. Se busca, ordenação ou categoria mudam, crie um novo fluxo de paginação com flatMapLatest ou invalide o PagingSource de forma explícita.\nO quinto erro é ignorar testes. Paginação parece visual, mas boa parte da lógica está em PagingSource, repository e mediator. Isso pode ser testado na JVM.\nTestando PagingSource Um teste simples valida se a primeira página retorna os dados esperados:\n@Test fun `deve carregar primeira pagina de produtos`() = runTest { val api = FakeProdutosApi( produtos = listOf( Produto(id = \u0026#34;1\u0026#34;, nome = \u0026#34;Café\u0026#34;), Produto(id = \u0026#34;2\u0026#34;, nome = \u0026#34;Chá\u0026#34;), ), ) val source = ProdutosPagingSource(api = api, termo = \u0026#34;\u0026#34;) val resultado = source.load( PagingSource.LoadParams.Refresh( key = null, loadSize = 20, placeholdersEnabled = false, ), ) assertEquals( PagingSource.LoadResult.Page( data = api.produtos, prevKey = null, nextKey = 2, ), resultado, ) } Em mediators, teste cenários de refresh, append, erro HTTP, banco vazio e banco já populado. Para fluxos com PagingData, use ferramentas do próprio Paging e, quando fizer sentido, combine com estratégias de teste já abordadas no guia de testes Android com Kotlin, Compose e Maestro.\nComo isso ajuda carreira e produto Paging 3 aparece com frequência em apps usados em produção porque resolve um problema que quase toda empresa tem: listas grandes com rede imperfeita. Para carreira Android, saber explicar PagingSource, RemoteMediator, LoadState, Room e Compose em conjunto demonstra maturidade além do CRUD básico.\nPara produto, a vantagem é concreta: menos travamento, menos dados baixados sem necessidade, primeira tela mais rápida e experiência melhor quando o usuário navega por catálogos, históricos ou feeds extensos. Em times backend, esse mesmo cuidado força contratos de API melhores, com paginação consistente por cursor, metadados claros e respostas previsíveis. Se você trabalha também no servidor, vale comparar esse desenho com APIs Kotlin em Ktor ou com alternativas de alta performance em Go para backend.\nConclusão Paging 3 não é apenas uma biblioteca para “carregar mais itens”. Ele organiza uma parte crítica da experiência Android: como dados grandes entram na tela sem desperdiçar rede, memória ou paciência do usuário. Em Kotlin, a combinação de Flow, PagingData, Room, RemoteMediator e Jetpack Compose cria uma arquitetura moderna e testável para listas grandes.\nComece simples com PagingSource quando a API remota já resolve o caso. Evolua para Room e RemoteMediator quando a experiência precisa ser offline-first. Trate LoadState com cuidado, preserve itens já carregados em erros de próxima página e mantenha o Pager fora da recomposição. Esses detalhes separam uma lista que “funciona no demo” de uma tela pronta para produção em 2026.\n","permalink":"https://kotlin.dev.br/blog/paging-3-kotlin-compose-2026/","summary":"\u003cp\u003eListas grandes parecem simples até o app começar a travar, repetir itens, perder posição de rolagem ou baixar milhares de registros de uma vez. Em apps Android reais, feeds, catálogos, históricos, chats, pedidos, notificações, resultados de busca e telas administrativas raramente cabem em uma única resposta HTTP. É nesse ponto que \u003cstrong\u003ePaging 3 com Kotlin e Jetpack Compose\u003c/strong\u003e deixa de ser detalhe de performance e vira parte importante da arquitetura.\u003c/p\u003e","title":"Paging 3 com Kotlin e Compose: Listas Grandes em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA GFT busca uma pessoa Desenvolvedora Android Pleno/Sênior para atuação presencial em Alphaville, São Paulo.\nResponsabilidadesDesenvolver e manter aplicações Android usando Kotlin.Construir interfaces mobile com Jetpack Compose.Integrar aplicações com APIs REST, WebSocket e Firebase.Colaborar com práticas de CI/CD e versionamento com Git.RequisitosExperiência em desenvolvimento Android.Conhecimento em Kotlin e Jetpack Compose.Experiência com integrações REST e WebSocket.Familiaridade com Firebase, Git e pipelines de CI/CD.Disponibilidade para trabalho presencial em Alphaville. ","permalink":"https://kotlin.dev.br/vagas/4bs7r07i1iyeoryb-gft-desenvolvedor-a-android-pleno-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA GFT busca uma pessoa Desenvolvedora Android Pleno/Sênior para atuação presencial em Alphaville, São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android usando Kotlin.\u003c/li\u003e\u003cli\u003eConstruir interfaces mobile com Jetpack Compose.\u003c/li\u003e\u003cli\u003eIntegrar aplicações com APIs REST, WebSocket e Firebase.\u003c/li\u003e\u003cli\u003eColaborar com práticas de CI/CD e versionamento com Git.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin e Jetpack Compose.\u003c/li\u003e\u003cli\u003eExperiência com integrações REST e WebSocket.\u003c/li\u003e\u003cli\u003eFamiliaridade com Firebase, Git e pipelines de CI/CD.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho presencial em Alphaville.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Android Pleno/Sênior"},{"content":"Sobre a vagaOportunidade de estágio em QA Automation no programa iXp da SAP Concur. Você atuará no desenvolvimento e manutenção de testes automatizados para garantir a qualidade de nossas soluções.\nResponsabilidadesDesenvolver e executar testes automatizados utilizando ferramentas modernasColaborar com equipes de desenvolvimento e QADocumentar casos de teste e resultadosParticipar de code reviews e melhorias contínuasInvestigar e reportar defeitos encontradosRequisitosConhecimento em automação de testes (Selenium, Playwright ou Cypress)Familiaridade com JavaScript, TypeScript ou JavaCompreensão de testes unitários e de integraçãoCapacidade de trabalhar em equipePortuguês fluenteDiferenciaisExperiência com Kotlin ou Node.jsConhecimento em JUnit, TestNG ou JestFamiliaridade com CI/CD (Jenkins, GitHub Actions)Experiência com testes de API (RestAssured, Postman)Conhecimento em BDD (Cucumber, Karate)BenefíciosPrograma de desenvolvimento estruturadoMentoria de profissionais experientesAmbiente híbridoOportunidade de carreira na SAP ","permalink":"https://kotlin.dev.br/vagas/tiyydbtenxpovrzo-sap-sap-concur-ixp-intern-qa-automation/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eOportunidade de estágio em QA Automation no programa iXp da SAP Concur. Você atuará no desenvolvimento e manutenção de testes automatizados para garantir a qualidade de nossas soluções.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e executar testes automatizados utilizando ferramentas modernas\u003c/li\u003e\u003cli\u003eColaborar com equipes de desenvolvimento e QA\u003c/li\u003e\u003cli\u003eDocumentar casos de teste e resultados\u003c/li\u003e\u003cli\u003eParticipar de code reviews e melhorias contínuas\u003c/li\u003e\u003cli\u003eInvestigar e reportar defeitos encontrados\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eConhecimento em automação de testes (Selenium, Playwright ou Cypress)\u003c/li\u003e\u003cli\u003eFamiliaridade com JavaScript, TypeScript ou Java\u003c/li\u003e\u003cli\u003eCompreensão de testes unitários e de integração\u003c/li\u003e\u003cli\u003eCapacidade de trabalhar em equipe\u003c/li\u003e\u003cli\u003ePortuguês fluente\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin ou Node.js\u003c/li\u003e\u003cli\u003eConhecimento em JUnit, TestNG ou Jest\u003c/li\u003e\u003cli\u003eFamiliaridade com CI/CD (Jenkins, GitHub Actions)\u003c/li\u003e\u003cli\u003eExperiência com testes de API (RestAssured, Postman)\u003c/li\u003e\u003cli\u003eConhecimento em BDD (Cucumber, Karate)\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eBenefícios\u003c/h3\u003e\u003cul\u003e\u003cli\u003ePrograma de desenvolvimento estruturado\u003c/li\u003e\u003cli\u003eMentoria de profissionais experientes\u003c/li\u003e\u003cli\u003eAmbiente híbrido\u003c/li\u003e\u003cli\u003eOportunidade de carreira na SAP\u003c/li\u003e\u003c/ul\u003e","title":"SAP Concur iXp Intern - QA Automation"},{"content":"Sobre a vagaA Very Good Ventures está buscando um Senior Backend \u0026 Infrastructure Engineer experiente para atuar remotamente. Você trabalharácom arquitetura de sistemas, infraestrutura em nuvem e desenvolvimento backend de alto desempenho.\nResponsabilidadesProjetar e implementar soluções de backend escaláveisGerenciar infraestrutura em nuvem com Kubernetes e DockerImplementar CI/CD pipelines robustosColaborar com times multidisciplinaresOtimizar performance e confiabilidade de sistemasRequisitosExperiência sênior em engenharia de backendProficiência em Terraform ou OpenTofuConhecimento prático de Kubernetes e DockerExperiência com pelo menos uma das linguagens: Kotlin, Go, Python, TypeScript, Java ou RustExpertise em CI/CDSólido entendimento de arquitetura de sistemas distribuídosTecnologiasKubernetes, Docker, Terraform, OpenTofu, CI/CD, GraphQL, Python, TypeScript, Go, Java, Kotlin, Rust\n","permalink":"https://kotlin.dev.br/vagas/l4zgf8rqqz1priv3-very-good-ventures-senior-backend-infrastructure-engineer/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Very Good Ventures está buscando um Senior Backend \u0026 Infrastructure Engineer experiente para atuar remotamente. Você trabalharácom arquitetura de sistemas, infraestrutura em nuvem e desenvolvimento backend de alto desempenho.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eProjetar e implementar soluções de backend escaláveis\u003c/li\u003e\u003cli\u003eGerenciar infraestrutura em nuvem com Kubernetes e Docker\u003c/li\u003e\u003cli\u003eImplementar CI/CD pipelines robustos\u003c/li\u003e\u003cli\u003eColaborar com times multidisciplinares\u003c/li\u003e\u003cli\u003eOtimizar performance e confiabilidade de sistemas\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de backend\u003c/li\u003e\u003cli\u003eProficiência em Terraform ou OpenTofu\u003c/li\u003e\u003cli\u003eConhecimento prático de Kubernetes e Docker\u003c/li\u003e\u003cli\u003eExperiência com pelo menos uma das linguagens: Kotlin, Go, Python, TypeScript, Java ou Rust\u003c/li\u003e\u003cli\u003eExpertise em CI/CD\u003c/li\u003e\u003cli\u003eSólido entendimento de arquitetura de sistemas distribuídos\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cp\u003eKubernetes, Docker, Terraform, OpenTofu, CI/CD, GraphQL, Python, TypeScript, Go, Java, Kotlin, Rust\u003c/p\u003e","title":"Senior Backend \u0026 Infrastructure Engineer"},{"content":"Aplicações Kotlin modernas quase sempre dependem de chamadas HTTP: gateway de pagamento, antifraude, catálogo, autenticação, serviço interno, API de parceiro, feature flag, geocoding, push notification ou modelo de IA. O problema é que rede falha de formas pouco educadas. Uma chamada pode demorar demais, cair no meio da resposta, retornar 429, saturar em horário de pico ou funcionar para 99% dos usuários e travar exatamente no fluxo mais importante do produto.\nPor isso, um Ktor Client resiliente não é apenas um detalhe de infraestrutura. Ele é parte da arquitetura da aplicação. Em 2026, times Kotlin que trabalham com backend, Android offline-first ou Kotlin Multiplatform precisam tratar timeout, retry, fallback, circuit breaker e observabilidade como requisitos normais de integração, não como remendos depois do primeiro incidente.\nEste guia mostra um caminho pragmático para configurar chamadas HTTP com Ktor Client usando coroutines, limites claros e decisões que reduzem risco em produção. Se você ainda está montando a base server-side, leia também o guia de Kotlin para backend, o tutorial de Ktor para APIs e o artigo sobre observabilidade em Kotlin.\nO erro comum: cliente HTTP sem política O anti-padrão mais frequente é criar um HttpClient genérico, chamar get() ou post() diretamente no repository e deixar cada tela ou endpoint lidar com falhas do jeito que conseguir. Isso funciona em demo, mas cria comportamento imprevisível quando a dependência externa começa a oscilar.\nSem política explícita, perguntas importantes ficam sem resposta:\nqual é o tempo máximo aceitável para a chamada; quais erros merecem retry; quantas tentativas são razoáveis; o que acontece se o serviço parceiro fica fora por cinco minutos; qual log ou métrica permite investigar a falha; se a operação pode ser repetida sem duplicar efeito colateral. Em sistemas distribuídos, ausência de decisão também é decisão. Só que normalmente é a pior: esperar demais, repetir demais, esconder erro demais ou derrubar o usuário por uma falha que poderia ter fallback.\nComece pelo timeout correto Timeout é a primeira camada de resiliência. Sem ele, uma chamada lenta consome coroutine, thread do engine, conexão e atenção operacional por tempo indefinido. No Ktor Client, o plugin HttpTimeout permite separar timeout total da requisição, timeout de conexão e timeout de socket.\nimport io.ktor.client.HttpClient import io.ktor.client.engine.cio.CIO import io.ktor.client.plugins.HttpTimeout val client = HttpClient(CIO) { install(HttpTimeout) { requestTimeoutMillis = 3_000 connectTimeoutMillis = 1_000 socketTimeoutMillis = 2_000 } } Esses números não são universais. Um checkout pode exigir resposta rápida; um relatório assíncrono pode tolerar mais tempo; uma chamada para API interna no mesmo cluster deveria ser mais curta que uma chamada para parceiro externo. O importante é escolher intencionalmente e revisar com base em métricas reais.\nTambém vale evitar um único cliente global para todos os destinos quando as políticas são muito diferentes. Um client para pagamentos pode ter timeout, headers e logs distintos de um client para catálogo público.\nRetry não é solução mágica Retry ajuda quando a falha é temporária. Ele piora o incidente quando a dependência está saturada e todos os consumidores começam a repetir chamadas ao mesmo tempo. A regra prática é: faça retry apenas para erros provavelmente transitórios, com limite baixo e backoff.\nNo Ktor, o plugin HttpRequestRetry cobre os casos comuns:\nimport io.ktor.client.plugins.HttpRequestRetry val client = HttpClient(CIO) { install(HttpTimeout) { requestTimeoutMillis = 3_000 connectTimeoutMillis = 1_000 socketTimeoutMillis = 2_000 } install(HttpRequestRetry) { maxRetries = 2 retryIf { _, response -\u0026gt; response.status.value in listOf(429, 502, 503, 504) } retryOnExceptionIf { _, cause -\u0026gt; cause is java.io.IOException } exponentialDelay() } } Repare no limite: duas novas tentativas já podem transformar uma chamada em três requests. Em alto volume, isso pesa. Para endpoints críticos, monitore taxa de retry como métrica própria. Se ela sobe, você tem sinal de degradação antes de o erro final aparecer para o usuário.\nOutro ponto essencial é idempotência. GET normalmente pode ser repetido. POST de pagamento, criação de pedido ou envio de mensagem não deve ser repetido sem uma chave idempotente. Se a operação produz efeito colateral, envie um identificador único, registre o estado local e combine com o backend o comportamento para duplicidade.\nModele resposta de erro como contrato Jogar exceção genérica para cima parece simples, mas empurra complexidade para quem chama. Uma abordagem mais saudável é traduzir a chamada externa para um resultado de domínio.\nsealed interface ResultadoParceiro\u0026lt;out T\u0026gt; { data class Sucesso\u0026lt;T\u0026gt;(val valor: T) : ResultadoParceiro\u0026lt;T\u0026gt; data class Indisponivel(val motivo: String) : ResultadoParceiro\u0026lt;Nothing\u0026gt; data class Rejeitado(val codigo: String) : ResultadoParceiro\u0026lt;Nothing\u0026gt; } class ParceiroClient(private val http: HttpClient) { suspend fun buscarLimite(clienteId: String): ResultadoParceiro\u0026lt;LimiteDto\u0026gt; { return try { val resposta = http.get(\u0026#34;https://api.parceiro.example/limites/$clienteId\u0026#34;) when (resposta.status.value) { 200 -\u0026gt; ResultadoParceiro.Sucesso(resposta.body()) 404 -\u0026gt; ResultadoParceiro.Rejeitado(\u0026#34;cliente_nao_encontrado\u0026#34;) in 500..599 -\u0026gt; ResultadoParceiro.Indisponivel(\u0026#34;parceiro_instavel\u0026#34;) else -\u0026gt; ResultadoParceiro.Indisponivel(\u0026#34;resposta_inesperada\u0026#34;) } } catch (e: Exception) { ResultadoParceiro.Indisponivel(\u0026#34;falha_http\u0026#34;) } } } O exemplo é pequeno, mas mostra a ideia: o restante da aplicação não precisa saber se a falha veio de timeout, DNS, 503 ou socket fechado. Ele precisa saber se pode seguir com fallback, pedir nova tentativa ao usuário ou interromper o fluxo.\nQuando usar circuit breaker Circuit breaker é útil quando uma dependência externa está falhando repetidamente e continuar chamando só aumenta latência e pressão. Ele “abre o circuito” por um período, falhando rápido ou usando fallback até que uma janela de teste indique recuperação.\nEm projetos JVM, uma escolha comum é usar Resilience4j ao redor da chamada suspensa. Em Kotlin, cuide para não bloquear threads e para manter o contrato de coroutine claro.\nclass CatalogoService( private val parceiro: ParceiroClient, private val cache: CatalogoCache, ) { suspend fun buscarProduto(id: String): ProdutoResumo { val resultado = parceiro.buscarProduto(id) return when (resultado) { is ResultadoParceiro.Sucesso -\u0026gt; { cache.salvar(id, resultado.valor) resultado.valor } is ResultadoParceiro.Indisponivel -\u0026gt; { cache.buscar(id) ?: ProdutoResumo.indisponivel(id) } is ResultadoParceiro.Rejeitado -\u0026gt; { ProdutoResumo.naoEncontrado(id) } } } } Nem todo sistema precisa de circuit breaker no primeiro dia. Para muitos produtos, timeout curto, retry controlado, fallback e boas métricas resolvem 80% do problema. Circuit breaker entra quando a dependência é crítica, o volume é alto ou incidentes anteriores mostraram cascata de falhas.\nFallback precisa ser honesto Fallback não é fingir que tudo está normal. É oferecer uma resposta degradada, segura e compreensível. Em um app de conteúdo, pode ser mostrar cache antigo com aviso de atualização. Em um checkout, pode ser bloquear uma opção de pagamento temporariamente. Em um dashboard interno, pode ser exibir dados parciais.\nO pior fallback é silencioso e enganoso. Se a informação está desatualizada, deixe isso claro no modelo. Se uma recomendação não pôde ser calculada, não invente. A confiabilidade percebida do produto depende tanto do comportamento em falha quanto do comportamento em sucesso.\nObservabilidade: log, métrica e trace Resiliência sem observabilidade vira chute. Cada chamada relevante deveria permitir responder: qual destino foi chamado, quanto demorou, quantas tentativas ocorreram, qual status voltou, se o fallback foi usado e qual correlação liga a chamada ao request original.\nPara APIs Kotlin, combine logs estruturados, métricas com Micrometer ou OpenTelemetry e traces distribuídos. Se o projeto já usa mensageria, vale conectar essa disciplina ao que foi discutido em Kotlin com Kafka e RabbitMQ: duplicidade, retry e dead letter queue são parentes próximos dos mesmos problemas em HTTP.\nUm conjunto mínimo de métricas para client HTTP inclui:\nduração por destino e rota lógica; contagem de status 2xx, 4xx, 5xx e exceções; quantidade de retries; quantidade de fallbacks; circuit breaker aberto, meio aberto ou fechado; timeout por dependência. No ecossistema de infraestrutura, muitas ferramentas usadas para observar essas chamadas nasceram em Go. Para comparar modelos de backend e operação, o portal Go Brasil é um bom complemento para quem trabalha com microsserviços, Prometheus, Kubernetes e ferramentas cloud-native.\nChecklist para produção Antes de considerar uma integração HTTP pronta para produção, revise:\nTimeout definido por destino, não herdado por acaso. Retry limitado a erros transitórios, com backoff e métrica. Operações com efeito colateral protegidas por idempotência. Resultado traduzido para contrato de domínio, não exceção genérica espalhada. Fallback explícito e honesto quando fizer sentido. Logs estruturados sem vazar token, CPF, cartão ou segredo. Métricas e tracing suficientes para investigar incidente. Testes cobrindo sucesso, 404, 429, 5xx, timeout e exceção de rede. Esse checklist também ajuda em entrevistas de backend Kotlin. Ele mostra maturidade além do “sei chamar uma API”: você demonstra que entende falhas reais, custo operacional e experiência do usuário.\nConclusão Ktor Client é uma ótima ferramenta para integrações HTTP em Kotlin porque combina API idiomática, coroutines e flexibilidade multiplataforma. Mas a qualidade da integração depende das políticas ao redor dele. Timeout evita espera infinita. Retry corrige falhas transitórias sem virar tempestade quando bem limitado. Circuit breaker protege o sistema de cascatas. Fallback preserva experiência quando a dependência degrada. Observabilidade transforma falha em diagnóstico.\nSe você está construindo backend Kotlin em 2026, não deixe resiliência para depois. Comece simples, com limites claros e métricas úteis. Depois evolua conforme volume, criticidade e histórico de incidentes. Esse é o caminho para criar aplicações Kotlin que não apenas funcionam no ambiente local, mas continuam se comportando bem quando a rede, os parceiros e a produção fazem o que sempre fazem: falham de vez em quando.\n","permalink":"https://kotlin.dev.br/blog/ktor-client-resiliente-timeout-retry-circuit-breaker-2026/","summary":"\u003cp\u003eAplicações Kotlin modernas quase sempre dependem de chamadas HTTP: gateway de pagamento, antifraude, catálogo, autenticação, serviço interno, API de parceiro, feature flag, geocoding, push notification ou modelo de IA. O problema é que rede falha de formas pouco educadas. Uma chamada pode demorar demais, cair no meio da resposta, retornar \u003ccode\u003e429\u003c/code\u003e, saturar em horário de pico ou funcionar para 99% dos usuários e travar exatamente no fluxo mais importante do produto.\u003c/p\u003e","title":"Ktor Client Resiliente: Timeout, Retry e Circuit Breaker em 2026 | Kotlin Brasil"},{"content":"Escolher entre Koin e Hilt parece uma decisão pequena no começo de um app Android em Kotlin. Na prática, ela influencia tempo de build, onboarding do time, testes, modularização, integração com Jetpack Compose, suporte a Kotlin Multiplatform e até a forma como erros aparecem em produção. Em 2026, as duas opções são maduras, mas resolvem o problema de injeção de dependência com filosofias bem diferentes.\nHilt é a escolha oficial do ecossistema Android, construída sobre Dagger, com validação forte em tempo de compilação e integração profunda com ViewModel, WorkManager, Navigation, instrumented tests e componentes Android. Koin é mais leve na experiência de uso: usa DSL Kotlin, exige menos anotações, costuma ser mais fácil de explicar para quem está aprendendo e funciona bem em projetos multiplataforma.\nA pergunta certa não é “qual é melhor?”. A pergunta certa é: qual reduz risco para o tipo de projeto, time e arquitetura que você tem agora? Este guia compara Koin e Hilt com critérios práticos para apps Android modernos escritos em Kotlin.\nO que DI precisa resolver em um app Kotlin Injeção de dependência não serve apenas para “evitar new”. Ela cria um contrato claro entre camadas. Um ViewModel não deve saber como construir um client HTTP, abrir banco local, configurar logger, montar repository ou escolher implementação fake em teste. Ele deve receber dependências prontas e focar no estado da tela.\nEm um app Android real, DI normalmente conecta:\nclients HTTP com Ktor, Retrofit ou GraphQL; DAOs do Room e stores locais; repositories e use cases; dispatchers de coroutines; loggers, feature flags e analytics; workers em background; ViewModels usados por telas Compose ou Fragments; implementações fake para testes. Se você ainda está estruturando camadas, vale revisar também o guia de Clean Architecture em Kotlin, MVVM com Kotlin e o guia base de injeção de dependência em Kotlin.\nKoin: DSL Kotlin, menos cerimônia Koin costuma agradar porque o código parece Kotlin comum. Você declara módulos com single, factory e viewModel, depois resolve dependências com get() ou APIs próprias para Android e Compose.\nval appModule = module { single { HttpClientFactory.create() } single\u0026lt;UsuarioApi\u0026gt; { UsuarioApiKtor(get()) } single\u0026lt;UsuarioRepository\u0026gt; { UsuarioRepositoryImpl(get()) } factory { ObservarPerfilUseCase(get()) } viewModel { PerfilViewModel(get()) } } Para muitos times, isso reduz fricção. Um desenvolvedor que já entende Kotlin consegue ler o grafo sem aprender Dagger imediatamente. Também é simples criar módulos diferentes para teste, preview ou ambiente local.\nval testeModule = module { single\u0026lt;UsuarioRepository\u0026gt; { FakeUsuarioRepository() } } O ponto de atenção é que parte dos erros aparece em runtime. Se você esquece uma dependência ou cria um ciclo ruim, o app pode compilar e falhar ao iniciar a tela ou o teste. Koin tem recursos de verificação, mas o time precisa colocá-los no pipeline. Sem essa disciplina, a simplicidade inicial vira risco.\nHilt: validação forte e integração Android Hilt usa anotações e geração de código para montar o grafo. A configuração parece mais verbosa, mas o ganho é que muitos problemas são detectados no build. Para apps grandes, essa previsibilidade pesa.\n@HiltViewModel class PerfilViewModel @Inject constructor( private val observarPerfil: ObservarPerfilUseCase, ) : ViewModel() Um módulo típico fica assim:\n@Module @InstallIn(SingletonComponent::class) abstract class RepositoryModule { @Binds @Singleton abstract fun bindUsuarioRepository( impl: UsuarioRepositoryImpl, ): UsuarioRepository } A integração com Android também é forte. @AndroidEntryPoint, @HiltViewModel, @ApplicationContext, scopes, testes instrumentados e integrações oficiais reduzem decisões manuais. Se seu app é Android puro, com muitos módulos e equipe acostumada a ferramentas Google, Hilt tende a ser uma escolha segura.\nO custo aparece em build e curva de aprendizado. Mensagens de erro de Dagger podem assustar no começo. Projetos muito pequenos podem sentir que há cerimônia demais para pouco ganho.\nComparação prática Critério Koin Hilt Curva de aprendizado Mais simples para Kotlin puro Mais íngreme por Dagger/anotações Validação Precisa de verificação/testes de grafo Forte em tempo de compilação Build Menos geração de código Pode aumentar tempo de build Runtime Resolução em runtime Grafo gerado/otimizado Android oficial Bom suporte Melhor integração oficial Compose Ergonomia boa com koinViewModel() Ergonomia boa com hiltViewModel() KMP Forte candidato Não é multiplatform Times grandes Funciona, mas exige disciplina Geralmente mais previsível Protótipos/MVPs Muito produtivo Pode ser excesso Essa tabela não deve ser lida como placar. Ela mostra trade-offs. Um app pequeno pode ficar excelente com Hilt se o time já domina Dagger. Um app grande pode usar Koin com sucesso se tiver verificação automatizada e arquitetura bem modularizada.\nJetpack Compose: as duas opções funcionam Em Compose, a tela deve receber estado e callbacks, não sair resolvendo dependência profunda. O lugar mais comum para DI é o ViewModel.\nCom Hilt:\n@Composable fun PerfilRoute( viewModel: PerfilViewModel = hiltViewModel(), ) { val state by viewModel.state.collectAsStateWithLifecycle() PerfilScreen( state = state, onRefresh = viewModel::refresh, ) } Com Koin:\n@Composable fun PerfilRoute( viewModel: PerfilViewModel = koinViewModel(), ) { val state by viewModel.state.collectAsStateWithLifecycle() PerfilScreen( state = state, onRefresh = viewModel::refresh, ) } A diferença não está no composable em si. Está no grafo por trás. Hilt tende a proteger mais em compile time. Koin tende a ser mais flexível para trocar módulos em testes, previews e projetos compartilhados.\nPara UI moderna, DI também conversa com temas como testes de screenshot no Compose, Android offline-first com Kotlin e WorkManager com Kotlin, porque todos eles dependem de repositories substituíveis e efeitos colaterais isolados.\nTestes: onde a decisão aparece rápido DI boa deixa teste mais barato. O ViewModel pode receber um repository fake; o repository pode receber um client fake; o worker pode receber um executor controlado.\nCom Hilt, testes instrumentados usam @HiltAndroidTest, HiltAndroidRule e substituição de módulos. É poderoso, mas exige configuração correta.\n@Module @TestInstallIn( components = [SingletonComponent::class], replaces = [RepositoryModule::class], ) object FakeRepositoryModule { @Provides fun provideUsuarioRepository(): UsuarioRepository = FakeUsuarioRepository() } Com Koin, a troca costuma ser direta:\n@Before fun setup() { startKoin { modules(appModule, testeModule) } } @After fun tearDown() { stopKoin() } A simplicidade de Koin é boa para testes unitários e módulos pequenos. Hilt brilha quando você quer testar o app Android inteiro com a mesma estrutura de produção e substituições explícitas.\nIndependentemente da ferramenta, não use DI como desculpa para esconder design ruim. Se um ViewModel precisa de dez dependências, talvez o problema seja falta de use cases ou responsabilidades misturadas. Se um repository cria threads, clients e DAOs internamente, a ferramenta de DI só está decorando acoplamento.\nPerformance e tempo de build Em runtime, Hilt tende a ser previsível porque o grafo foi gerado no build. Koin resolve dependências dinamicamente, mas em muitos apps o custo é irrelevante perto de rede, banco e renderização. O problema real costuma ser outro: tempo de build versus segurança.\nHilt pode deixar builds mais pesados, especialmente em projetos Android grandes com muitos módulos, kapt ou configuração antiga. KSP e melhorias no ecossistema ajudam, mas a geração de código ainda precisa ser considerada. Koin reduz essa carga, mas exige que o pipeline rode testes de inicialização do grafo.\nUma prática saudável com Koin é criar um teste que sobe o grafo principal e resolve componentes críticos. Ele não substitui todos os testes, mas pega dependências faltando antes de chegar ao usuário.\n@Test fun `grafo principal inicia`() { koinApplication { modules(appModule) }.checkModules() } A API exata pode variar conforme a versão do Koin, então confira a documentação atual. O ponto é cultural: se a ferramenta valida menos no compilador, o time precisa validar no CI.\nKotlin Multiplatform muda a conversa Se o projeto é Android puro, Hilt é candidato forte. Se o projeto usa Kotlin Multiplatform, Koin ganha espaço porque pode operar fora do Android. Em KMP, você pode compartilhar repositories, use cases, clients Ktor e configuração de módulos comuns.\nval sharedModule = module { single { Json { ignoreUnknownKeys = true } } single { ApiClient(get()) } single\u0026lt;ProdutoRepository\u0026gt; { ProdutoRepositoryImpl(get()) } } No Android, você complementa com dependências específicas da plataforma. No iOS, inicializa o grafo compartilhado de outra forma. Isso combina com a direção descrita no artigo sobre nova estrutura de projetos KMP em 2026 e no tutorial de Kotlin Multiplatform.\nHilt continua útil em um app Android que consome um módulo KMP, mas ele não resolve DI do lado iOS. Uma arquitetura híbrida é possível: Koin no módulo compartilhado e Hilt no app Android. Só tome cuidado para não criar dois mundos que ninguém entende.\nQuando escolher Koin Escolha Koin quando:\no time valoriza simplicidade e DSL Kotlin; o projeto é pequeno ou médio e precisa avançar rápido; há Kotlin Multiplatform no horizonte; você quer módulos fáceis de trocar em testes e previews; o time aceita adicionar verificação de grafo no CI; a equipe ainda não domina Dagger/Hilt e a cerimônia atrapalharia entrega. Koin é especialmente confortável para produtos em descoberta, apps internos, módulos compartilhados e times que preferem clareza explícita em Kotlin a anotações espalhadas. Só não trate Koin como “sem arquitetura”. Ele facilita resolver dependências, mas não decide seus limites de camada.\nQuando escolher Hilt Escolha Hilt quando:\no app é Android puro e deve crescer por anos; o time já conhece Dagger ou quer seguir o caminho oficial do Android; validação em tempo de compilação é prioridade; há muitos módulos, flavors, workers e testes instrumentados; você quer integração direta com ViewModel, Navigation e componentes Android; falhas de grafo em runtime seriam caras demais. Hilt é uma boa aposta para apps corporativos, fintechs, healthtechs, marketplaces e produtos com muitas telas e ciclos longos de manutenção. O custo de aprender a ferramenta tende a se pagar quando o grafo cresce.\nErros comuns O primeiro erro é misturar resolução de dependência dentro de composables de UI pura. Deixe a rota resolver o ViewModel e passe estado para o componente visual. Isso mantém previews e testes mais simples.\nO segundo é injetar tudo. Classes de domínio pequenas podem receber parâmetros normais. Nem toda função precisa virar service. DI deve reduzir acoplamento, não transformar o projeto em uma coleção de singletons.\nO terceiro é deixar scopes implícitos. Em Hilt, entenda SingletonComponent, ActivityRetainedComponent e escopos de ViewModel. Em Koin, diferencie single, factory e scopes quando realmente precisar deles.\nO quarto é ignorar observabilidade. Se uma dependência crítica falha ao inicializar, registre erro útil. Em apps backend ou Android com sincronização pesada, combine DI com observabilidade em Kotlin para entender falhas reais.\nRecomendação rápida Para um app Android profissional e grande em 2026, eu começaria por Hilt, principalmente se a equipe já trabalha no ecossistema Google e não há KMP planejado. A validação forte e a integração oficial reduzem risco no longo prazo.\nPara um projeto Kotlin Multiplatform, um MVP mobile, um app interno ou uma equipe que precisa de velocidade sem entrar no mundo Dagger agora, eu escolheria Koin e colocaria verificação do grafo no CI desde o primeiro dia.\nA escolha não precisa ser ideológica. O objetivo é manter dependências explícitas, testes viáveis e arquitetura compreensível. Koin e Hilt conseguem entregar isso quando usados com disciplina. O que não funciona é deixar cada tela construir seu próprio mundo.\nSe você está montando a base de um app Kotlin, leia também Kotlin para Android, testes com JUnit 5 e MockK, CI/CD para Kotlin e, para comparar com outras stacks de backend e automação, veja como Python Brasil aborda produtividade e testes.\n","permalink":"https://kotlin.dev.br/blog/koin-vs-hilt-kotlin-android-2026/","summary":"\u003cp\u003eEscolher entre \u003cstrong\u003eKoin\u003c/strong\u003e e \u003cstrong\u003eHilt\u003c/strong\u003e parece uma decisão pequena no começo de um app Android em Kotlin. Na prática, ela influencia tempo de build, onboarding do time, testes, modularização, integração com Jetpack Compose, suporte a Kotlin Multiplatform e até a forma como erros aparecem em produção. Em 2026, as duas opções são maduras, mas resolvem o problema de injeção de dependência com filosofias bem diferentes.\u003c/p\u003e\n\u003cp\u003eHilt é a escolha oficial do ecossistema Android, construída sobre Dagger, com validação forte em tempo de compilação e integração profunda com \u003ccode\u003eViewModel\u003c/code\u003e, \u003ccode\u003eWorkManager\u003c/code\u003e, Navigation, instrumented tests e componentes Android. Koin é mais leve na experiência de uso: usa DSL Kotlin, exige menos anotações, costuma ser mais fácil de explicar para quem está aprendendo e funciona bem em projetos multiplataforma.\u003c/p\u003e","title":"Koin ou Hilt em Kotlin: Como Escolher DI no Android em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA CI\u0026amp;T busca uma pessoa Desenvolvedora Backend Java/Kotlin Pleno para atuação remota no Brasil.\nStack principalJava e KotlinSpring BootAWSSQS e SNSAthenaPostgreSQLAutomação de testesRequisitosExperiência em desenvolvimento backend com Java e Kotlin.Conhecimento em Spring Boot para criação e manutenção de APIs e serviços.Experiência com serviços AWS, incluindo SQS, SNS e Athena.Vivência com PostgreSQL.Prática com automação de testes.Modelo de trabalhoVaga remota para profissionais no Brasil.\n","permalink":"https://kotlin.dev.br/vagas/rng2kumrrsujp0ve-ci-t-desenvolvedor-backend-java-kotlin-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026amp;T busca uma pessoa Desenvolvedora Backend Java/Kotlin Pleno para atuação remota no Brasil.\u003c/p\u003e\u003ch3\u003eStack principal\u003c/h3\u003e\u003cul\u003e\u003cli\u003eJava e Kotlin\u003c/li\u003e\u003cli\u003eSpring Boot\u003c/li\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eSQS e SNS\u003c/li\u003e\u003cli\u003eAthena\u003c/li\u003e\u003cli\u003ePostgreSQL\u003c/li\u003e\u003cli\u003eAutomação de testes\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento backend com Java e Kotlin.\u003c/li\u003e\u003cli\u003eConhecimento em Spring Boot para criação e manutenção de APIs e serviços.\u003c/li\u003e\u003cli\u003eExperiência com serviços AWS, incluindo SQS, SNS e Athena.\u003c/li\u003e\u003cli\u003eVivência com PostgreSQL.\u003c/li\u003e\u003cli\u003ePrática com automação de testes.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais no Brasil.\u003c/p\u003e","title":"Desenvolvedor Backend Java/Kotlin Pleno"},{"content":"Sobre a vagaA Zup Innovation busca uma Pessoa Desenvolvedora Backend Kotlin Sênior para atuação remota, vinculada a São Paulo, Brasil.\nStack e contexto técnicoKotlin para desenvolvimento Backend.AWS, incluindo API Gateway, DynamoDB, S3, Lambda e EC2.APIs REST.Git para versionamento de código.SenioridadeVaga de nível sênior.\n","permalink":"https://kotlin.dev.br/vagas/dfhc8bskg6d1jsvp-zup-innovation-pessoa-desenvolvedora-backend-kotlin-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Zup Innovation busca uma Pessoa Desenvolvedora Backend Kotlin Sênior para atuação remota, vinculada a São Paulo, Brasil.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin para desenvolvimento Backend.\u003c/li\u003e\u003cli\u003eAWS, incluindo API Gateway, DynamoDB, S3, Lambda e EC2.\u003c/li\u003e\u003cli\u003eAPIs REST.\u003c/li\u003e\u003cli\u003eGit para versionamento de código.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade\u003c/h3\u003e\u003cp\u003eVaga de nível sênior.\u003c/p\u003e","title":"Pessoa Desenvolvedora Backend Kotlin Sênior"},{"content":"Sobre a vagaVaga sênior de Backend no C6 Bank para atuação presencial em São Paulo, com foco em Kotlin, Java, Spring Boot e arquitetura de microsserviços.\nResponsabilidadesDesenvolver e manter serviços backend com Kotlin e Java.Trabalhar com microsserviços, fluxos assíncronos e arquitetura orientada a eventos.Integrar sistemas usando Kafka, SQS e SNS.Atuar com bancos de dados relacionais e NoSQL, incluindo PostgreSQL, MongoDB e Cassandra.Apoiar práticas de observabilidade, segurança e infraestrutura como código em ambiente AWS.RequisitosExperiência sênior em desenvolvimento backend.Conhecimento sólido em Kotlin, Java e Spring Boot.Vivência com microsserviços e sistemas distribuídos.Experiência com Kafka, mensageria e processamento assíncrono.Conhecimento em PostgreSQL, MongoDB ou Cassandra.Experiência com AWS, observabilidade, protocolos de segurança e infraestrutura como código. ","permalink":"https://kotlin.dev.br/vagas/6urq2l36t28ng1xz-c6-bank-pessoa-desenvolvedora-backend-senior-kotlin-java/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga sênior de Backend no C6 Bank para atuação presencial em São Paulo, com foco em Kotlin, Java, Spring Boot e arquitetura de microsserviços.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend com Kotlin e Java.\u003c/li\u003e\u003cli\u003eTrabalhar com microsserviços, fluxos assíncronos e arquitetura orientada a eventos.\u003c/li\u003e\u003cli\u003eIntegrar sistemas usando Kafka, SQS e SNS.\u003c/li\u003e\u003cli\u003eAtuar com bancos de dados relacionais e NoSQL, incluindo PostgreSQL, MongoDB e Cassandra.\u003c/li\u003e\u003cli\u003eApoiar práticas de observabilidade, segurança e infraestrutura como código em ambiente AWS.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento backend.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin, Java e Spring Boot.\u003c/li\u003e\u003cli\u003eVivência com microsserviços e sistemas distribuídos.\u003c/li\u003e\u003cli\u003eExperiência com Kafka, mensageria e processamento assíncrono.\u003c/li\u003e\u003cli\u003eConhecimento em PostgreSQL, MongoDB ou Cassandra.\u003c/li\u003e\u003cli\u003eExperiência com AWS, observabilidade, protocolos de segurança e infraestrutura como código.\u003c/li\u003e\u003c/ul\u003e","title":"Pessoa Desenvolvedora Backend Sênior Kotlin/Java"},{"content":"WorkManager é uma das bibliotecas mais importantes do Android moderno para quem precisa executar trabalho em segundo plano de forma confiável. Em apps reais, nem tudo deve acontecer enquanto a tela está aberta: sincronizar dados pendentes, enviar logs, fazer upload de arquivos, baixar conteúdo para uso offline, limpar cache antigo e reagendar tarefas depois de uma falha são necessidades comuns. Com Kotlin no Android, o caminho idiomático é combinar WorkManager, coroutines, constraints e uma arquitetura clara de repository.\nO erro comum é tratar WorkManager como “uma coroutine que roda depois”. Ele não é isso. WorkManager é um agendador persistente para trabalho adiado e garantido, respeitando condições do sistema como rede, bateria, armazenamento, reinício do aparelho e políticas do Android para background execution. Quando usado bem, ele deixa o app mais resiliente. Quando usado mal, vira uma fonte de workers duplicados, retries infinitos e consumo de bateria.\nEste guia mostra quando usar WorkManager, como criar um CoroutineWorker, como configurar restrições, retry, dados de entrada, execução única, testes e observabilidade. A ideia é complementar temas que aparecem em Android offline-first com Kotlin, Room, Flow e arquitetura Android para vagas em 2026.\nQuando usar WorkManager? Use WorkManager quando o trabalho precisa continuar sendo importante mesmo se o usuário sair da tela, fechar o app ou reiniciar o aparelho. Alguns exemplos clássicos:\nsincronizar operações criadas offline; enviar fotos ou anexos quando houver Wi-Fi; atualizar dados de catálogo em background; enviar eventos acumulados de analytics interno; limpar arquivos temporários antigos; baixar conteúdo para leitura offline; fazer retry de uma chamada que falhou por rede instável. Não use WorkManager para tudo. Se a ação precisa responder imediatamente ao clique do usuário, execute no ViewModel ou no repository com coroutines. Se é uma tarefa muito curta ligada ao ciclo de vida da tela, WorkManager adiciona complexidade desnecessária. Se precisa rodar exatamente em um horário preciso, talvez AlarmManager faça mais sentido. Se é streaming contínuo, use um foreground service bem justificado.\nUma regra prática: WorkManager é ideal para trabalho adiável, persistente e com garantia razoável de execução. Ele não promete execução instantânea. O sistema decide o melhor momento considerando bateria, rede e outras restrições.\nDependências básicas Em um projeto Android com Gradle Kotlin DSL, você normalmente adiciona a dependência do runtime Kotlin:\ndependencies { implementation(\u0026#34;androidx.work:work-runtime-ktx:2.10.0\u0026#34;) } Confira sempre a versão mais recente compatível com o seu projeto. Em apps com injeção de dependência, você também pode precisar de integração com Hilt ou uma WorkerFactory customizada.\nCriando um CoroutineWorker Para Kotlin, prefira CoroutineWorker em vez de bloquear uma thread manualmente. O método doWork() é suspend, então você pode chamar repositories, DAOs e APIs que já usam coroutines.\nclass SincronizarFavoritosWorker( appContext: Context, params: WorkerParameters, ) : CoroutineWorker(appContext, params) { override suspend fun doWork(): Result { val repository = ServiceLocator.favoritosRepository(applicationContext) return try { repository.sincronizarFavoritosPendentes() Result.success() } catch (e: IOException) { Result.retry() } catch (e: HttpException) { if (e.code() in 500..599) Result.retry() else Result.failure() } } } O exemplo usa ServiceLocator apenas para manter o código curto. Em produção, prefira injeção explícita com Hilt, Koin ou uma WorkerFactory. O worker não deve conter regra de negócio complexa. Ele deve coordenar a execução e delegar a lógica para um repository ou use case testável.\nEntendendo success, retry e failure O retorno do worker comunica ao WorkManager o que aconteceu:\nResult.success() indica que o trabalho terminou; Result.retry() pede nova tentativa com política de backoff; Result.failure() encerra a cadeia como falha definitiva. Não retorne retry() para qualquer erro. Falha de rede, timeout e erro 5xx costumam ser retryable. Erro 401, payload inválido ou regra de negócio rejeitada normalmente precisam de correção local, logout ou marcação da operação como falha definitiva. Retry infinito para erro permanente só gasta bateria e esconde o problema.\nEm apps offline-first, o repository pode guardar o status da operação pendente no Room. Assim, mesmo quando o worker retorna failure(), a UI consegue explicar o estado ao usuário: “Não foi possível sincronizar esta alteração. Toque para tentar novamente.”\nAgendando trabalho com constraints Constraints evitam executar trabalho no momento errado. Se a sincronização depende de internet, declare isso. Se o upload é grande, talvez exija Wi-Fi ou bateria não baixa.\nval constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .setRequiresBatteryNotLow(true) .build() val request = OneTimeWorkRequestBuilder\u0026lt;SincronizarFavoritosWorker\u0026gt;() .setConstraints(constraints) .setBackoffCriteria( BackoffPolicy.EXPONENTIAL, 30.seconds.toJavaDuration(), ) .addTag(\u0026#34;sync-favoritos\u0026#34;) .build() WorkManager.getInstance(context).enqueue(request) Use constraints com intenção. Exigir Wi-Fi para uma sincronização pequena pode atrasar o app sem necessidade. Não exigir rede para um worker que só chama API gera falhas previsíveis. A melhor configuração depende do impacto no usuário, tamanho dos dados e urgência da operação.\nEvitando workers duplicados Um dos problemas mais comuns é enfileirar o mesmo trabalho várias vezes. O usuário favoritou cinco itens? O app voltou da tela de login? A conectividade mudou? Sem cuidado, cada evento dispara um worker novo.\nPara sincronização de fila, geralmente faz sentido usar enqueueUniqueWork:\nWorkManager.getInstance(context).enqueueUniqueWork( \u0026#34;sync-favoritos\u0026#34;, ExistingWorkPolicy.KEEP, request, ) KEEP preserva um trabalho já pendente ou em execução. É uma boa opção quando “uma sincronização em andamento” já é suficiente. REPLACE cancela a anterior e agenda outra; use quando a nova solicitação realmente torna a antiga obsoleta. APPEND entra em cena quando você precisa encadear etapas, mas não deveria ser a primeira escolha para sync simples.\nO nome do trabalho único deve ser estável e específico. sync é amplo demais. sync-favoritos, upload-avatar ou limpeza-cache-noticias comunicam melhor a intenção.\nPassando dados de entrada Workers podem receber dados pequenos por Data. Isso é útil para IDs, flags e parâmetros simples.\nval input = workDataOf( \u0026#34;usuarioId\u0026#34; to usuarioId, \u0026#34;forcarRefresh\u0026#34; to true, ) val request = OneTimeWorkRequestBuilder\u0026lt;SincronizarPerfilWorker\u0026gt;() .setInputData(input) .build() Dentro do worker:\noverride suspend fun doWork(): Result { val usuarioId = inputData.getString(\u0026#34;usuarioId\u0026#34;) ?: return Result.failure() val forcarRefresh = inputData.getBoolean(\u0026#34;forcarRefresh\u0026#34;, false) repository.sincronizarPerfil(usuarioId, forcarRefresh) return Result.success() } Não coloque payload grande em Data. Se você precisa sincronizar muitas operações, grave a fila no Room e passe apenas um identificador ou nem passe nada. O worker lê o banco e decide o que está pendente.\nTrabalho periódico: use com cuidado WorkManager também suporta tarefas periódicas, mas elas não são cron de servidor. O Android pode atrasar a execução para preservar bateria. Use periodic work para manutenção eventual, não para lógica que precisa rodar em minuto exato.\nval request = PeriodicWorkRequestBuilder\u0026lt;AtualizarCatalogoWorker\u0026gt;( repeatInterval = 6.hours, ) .setConstraints( Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .build(), ) .build() WorkManager.getInstance(context).enqueueUniquePeriodicWork( \u0026#34;atualizar-catalogo\u0026#34;, ExistingPeriodicWorkPolicy.KEEP, request, ) Para dados que o usuário precisa ver imediatamente, combine periodic work com refresh manual ou refresh ao abrir a tela. O trabalho periódico mantém o app razoavelmente atualizado; ele não substitui uma boa estratégia de estado local e invalidação.\nWorkManager em arquitetura offline-first Em apps offline-first, WorkManager deve ser uma peça da arquitetura, não um atalho que acessa tudo diretamente. Ele costuma trabalhar ao lado de Room para dados estruturados e DataStore Preferences para metadados pequenos, como última sincronização ou filtro escolhido. Um desenho saudável fica assim:\nA UI envia uma intenção para o ViewModel. O repository grava a alteração local no Room. O repository marca a operação como pendente. O app agenda um worker único de sync. O worker chama o repository para processar pendências. O repository atualiza Room com sucesso, erro ou conflito. A UI observa o estado local via Flow. Essa separação mantém a tela rápida e previsível. O usuário vê a ação aplicada localmente, enquanto a sincronização acontece no momento apropriado. Se a API falha, o estado pendente continua visível e testável.\nObservando o estado do trabalho Você pode observar o estado de um work pelo ID ou por tag:\nval workInfos: Flow\u0026lt;List\u0026lt;WorkInfo\u0026gt;\u0026gt; = WorkManager.getInstance(context) .getWorkInfosByTagFlow(\u0026#34;sync-favoritos\u0026#34;) Esse estado é útil para debug e alguns indicadores de UI, mas não deveria ser a única fonte de verdade do produto. Para uma fila offline-first, o Room continua sendo mais confiável para responder “quantas operações estão pendentes?” ou “qual item falhou?”. WorkInfo explica a execução do worker; o banco explica o estado de negócio.\nTestando workers Teste a regra principal no repository com testes unitários. O worker deve ter pouco código, mas ainda vale validar retorno success, retry e failure quando possível. O WorkManager tem artefatos de teste para inicializar o ambiente em testes instrumentados.\nO que vale cobrir:\nerro de rede retorna retry; erro permanente retorna failure; sucesso chama o repository e limpa pendências; workers duplicados não são criados para o mesmo fluxo; constraints estão configuradas para rede quando necessário; a UI mostra estado pendente mesmo se o worker ainda não rodou. Se o app já usa JUnit e MockK, deixe a maior parte da complexidade fora do worker. Mockar WorkManager demais costuma deixar o teste frágil; testar o repository e fazer um smoke test do agendamento geralmente traz melhor retorno.\nErros comuns com WorkManager O primeiro erro é transformar worker em “classe Deus”. Worker não deve montar payload, decidir regra de negócio, manipular UI indireta e conhecer detalhes de API ao mesmo tempo. Delegue.\nO segundo erro é ignorar idempotência. Um worker pode rodar mais de uma vez depois de retry. Se enviar a mesma operação duas vezes quebra o backend, a operação precisa de identificador idempotente ou controle de status local.\nO terceiro erro é usar periodic work para tentar simular push notification. Se o servidor precisa avisar o app, use FCM ou outra estratégia apropriada. Periodic work atrasado por bateria não é canal de tempo real.\nO quarto erro é não registrar nada. Em produção, falhas de sync precisam de logs estruturados, contadores e, em casos críticos, alertas. Em apps Android, também vale registrar crashes, ANRs e exceções não fatais com Firebase Crashlytics em Kotlin. Para aprofundar esse lado, veja também observabilidade em Kotlin e CI/CD para Kotlin.\nChecklist prático Antes de colocar WorkManager em produção, valide:\no trabalho é realmente adiável e persistente; há constraints de rede/bateria coerentes; retries diferenciam erro temporário e permanente; o worker é idempotente; enqueueUniqueWork evita duplicação quando necessário; dados grandes ficam no Room, não no Data; a UI não depende apenas do WorkInfo para estado de negócio; logs e métricas permitem investigar falhas. Conclusão WorkManager com Kotlin é essencial para apps Android que precisam ser confiáveis fora do fluxo imediato da tela. Ele resolve execução adiada, retry e sobrevivência a reinício do app, mas não substitui arquitetura. A combinação mais forte em 2026 é usar CoroutineWorker como orquestrador fino, repositories para regra de negócio, Room para estado local, Flow para UI reativa e constraints para respeitar o dispositivo do usuário.\nPara quem está estudando Android ou montando portfólio, um projeto que usa WorkManager corretamente demonstra maturidade: você entende rede instável, bateria, sincronização, retries e experiência real de produto. Esse é exatamente o tipo de detalhe que diferencia um app de tutorial de um app pronto para produção.\n","permalink":"https://kotlin.dev.br/blog/workmanager-kotlin-android-2026/","summary":"\u003cp\u003eWorkManager é uma das bibliotecas mais importantes do Android moderno para quem precisa executar trabalho em segundo plano de forma confiável. Em apps reais, nem tudo deve acontecer enquanto a tela está aberta: sincronizar dados pendentes, enviar logs, fazer upload de arquivos, baixar conteúdo para uso offline, limpar cache antigo e reagendar tarefas depois de uma falha são necessidades comuns. Com \u003cstrong\u003eKotlin no Android\u003c/strong\u003e, o caminho idiomático é combinar WorkManager, coroutines, constraints e uma arquitetura clara de repository.\u003c/p\u003e","title":"WorkManager com Kotlin no Android: Tarefas em Segundo Plano em 2026 | Kotlin Brasil"},{"content":"Testes automatizados costumam entrar em projetos Android pela porta dos repositories, use cases e ViewModels. Isso é ótimo, mas deixa uma pergunta importante sem resposta: quem garante que a interface não quebrou visualmente? Um Text truncado, um botão sem contraste, um card desalinhado ou um estado vazio com espaçamento errado podem passar por testes unitários perfeitos. Em apps escritos com Jetpack Compose e Kotlin, os testes de screenshot ajudam a fechar essa lacuna.\nScreenshot testing não substitui teste unitário, teste de integração nem teste manual exploratório. Ele serve para detectar regressões visuais comparando uma imagem atual da UI com uma imagem de referência aprovada pelo time. Quando o diff aparece, alguém revisa: se a mudança era intencional, o baseline é atualizado; se era acidental, o código volta para o caminho correto.\nEsse tipo de validação ficou mais relevante em 2026 porque muitos times já adotaram Compose em produção, modularizaram design systems e passaram a entregar telas em ciclos curtos. Se você já estudou Jetpack Compose, MVVM com Kotlin e testes com JUnit 5 e MockK, screenshot testing é o próximo passo natural para proteger a camada visual.\nO que um teste de screenshot valida? Um teste de screenshot captura a renderização de um componente ou tela em um cenário controlado. Depois, compara essa captura com uma imagem salva no repositório ou em um artefato de referência. A validação responde perguntas como:\no layout continua respeitando o espaçamento esperado; o tema claro e o tema escuro ainda renderizam corretamente; estados de loading, erro e conteúdo real estão visíveis; textos longos não quebram o design; mudanças no design system não alteraram telas sem querer. Isso é especialmente útil em Compose porque componentes pequenos são fáceis de isolar. Você pode testar um ProdutoCard, um EmptyState, uma barra de filtros ou uma tela inteira com dados fake. Quanto menor o recorte, mais rápido o teste roda e mais fácil fica entender o diff.\nQuando vale a pena usar? O melhor uso não é fotografar todas as telas do app sem critério. Isso cria baselines demais, aumenta ruído no pull request e transforma cada ajuste de espaçamento em dor operacional. Comece pelos pontos de maior risco:\ncomponentes reutilizados em muitas telas; telas que impactam conversão, onboarding ou pagamento; estados vazios, erros e permissões negadas; design system compartilhado entre múltiplos módulos; telas com muito conteúdo dinâmico ou regras de responsividade. Um app de delivery, por exemplo, pode começar pelos cards de restaurante, carrinho, resumo do pedido e tela de erro de pagamento. Um app corporativo offline-first pode priorizar listas, estados de sincronização e alertas de conflito. O critério é simples: se uma regressão visual ali geraria bug perceptível para o usuário, vale considerar screenshot test.\nEstrutura recomendada no projeto Uma organização prática é separar três coisas: previews ou fixtures visuais, testes de screenshot e baselines. Em um módulo Android com Compose, a estrutura pode ficar assim:\napp/ src/ debug/ java/br/com/exemplo/ui/preview/ PedidoFixtures.kt screenshotTest/ java/br/com/exemplo/ui/ PedidoCardScreenshotTest.kt screenshots/ PedidoCard_light.png PedidoCard_dark.png Os detalhes mudam conforme a biblioteca usada, mas a disciplina é a mesma. Os dados usados no teste devem ser determinísticos. Nada de LocalDateTime.now() livre, URL remota, fonte baixada em runtime ou texto vindo de API. Quanto mais estável o cenário, menos falsos positivos aparecem.\nExemplo de componente testável Imagine um card simples de pedido. Ele recebe dados prontos, não busca nada sozinho e não depende de estado global. Isso torna o componente ideal para screenshot testing.\ndata class PedidoUi( val numero: String, val cliente: String, val status: String, val total: String, ) @Composable fun PedidoCard( pedido: PedidoUi, modifier: Modifier = Modifier, ) { Card(modifier = modifier.fillMaxWidth()) { Column(modifier = Modifier.padding(16.dp)) { Text( text = \u0026#34;Pedido #${pedido.numero}\u0026#34;, style = MaterialTheme.typography.titleMedium, ) Text(text = pedido.cliente) Spacer(modifier = Modifier.height(8.dp)) Text(text = pedido.status) Text( text = pedido.total, style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Bold, ) } } } O segredo está em manter o componente previsível. Se ele recebe PedidoUi, você consegue montar cenários claros: pedido novo, pedido cancelado, cliente com nome longo, total alto, status em duas linhas. Esses cenários também funcionam bem como @Preview, documentação viva para designers e referência para QA.\nExemplo conceitual de teste Cada ferramenta tem sua API, mas um teste de screenshot costuma seguir o mesmo fluxo: renderizar Compose, aplicar tema, capturar imagem e comparar com baseline.\nclass PedidoCardScreenshotTest { @get:Rule val composeRule = createComposeRule() @Test fun pedidoCard_estadoPago_temaClaro() { composeRule.setContent { KotlinBrasilTheme(darkTheme = false) { PedidoCard( pedido = PedidoUi( numero = \u0026#34;1042\u0026#34;, cliente = \u0026#34;Mariana Oliveira\u0026#34;, status = \u0026#34;Pagamento confirmado\u0026#34;, total = \u0026#34;R$ 149,90\u0026#34;, ), ) } } composeRule .onRoot() .captureToImage() .assertMatchesBaseline(\u0026#34;PedidoCard_estadoPago_temaClaro\u0026#34;) } } O método assertMatchesBaseline acima é ilustrativo. Na prática, ele pode vir de uma biblioteca específica ou de uma integração interna do time. O importante é que o teste tenha nome descritivo, cenário estável e baseline versionado.\nComo reduzir falsos positivos Screenshot testing fica ruim quando o ambiente muda demais. Diferenças de fonte, densidade, antialiasing, idioma, timezone e tamanho de tela podem gerar diffs sem mudança real de produto. Para evitar isso:\nfixe dimensões e densidade do dispositivo de teste; use dados fake determinísticos; evite relógio real, rede real e animações rodando; teste tema claro e escuro separadamente; padronize fonte e renderização no CI; mantenha tolerância visual baixa, mas não ingênua. Se o teste roda em emulador, o ambiente do CI precisa ser previsível. Se roda em renderização local no JVM, confira as limitações da ferramenta para componentes que dependem de APIs Android específicas. Em ambos os casos, documente como atualizar baselines. Nada pior do que um teste que falha corretamente, mas ninguém sabe revisar.\nIntegração com CI/CD O fluxo ideal em pull requests é simples: testes unitários continuam rodando primeiro; testes de screenshot entram depois, talvez apenas nos módulos de UI alterados; quando há diff, o CI publica os artefatos para revisão. O time então decide se a alteração visual é desejada.\nUm pipeline conceitual pode ter etapas assim:\nsteps: - name: Run unit tests run: ./gradlew testDebugUnitTest - name: Run screenshot tests run: ./gradlew validateDebugScreenshotTest - name: Upload screenshot diffs if: failure() uses: actions/upload-artifact@v4 with: name: screenshot-diffs path: app/build/reports/screenshot Se você já tem um pipeline parecido com o do nosso guia de CI/CD para Kotlin ou com GitHub Actions em projetos Kotlin, a lógica encaixa bem. A diferença é cultural: o reviewer precisa olhar o diff visual com a mesma seriedade que olha uma mudança de código.\nComo lidar com baselines no repositório Versionar baselines no Git costuma ser a escolha mais simples para times pequenos e médios. As imagens ficam próximas dos testes, cada alteração aparece no pull request e o histórico mostra quando a UI mudou. Para times maiores, pode fazer sentido armazenar baselines em um serviço dedicado, mas isso aumenta complexidade.\nAlgumas regras ajudam bastante:\nnão atualize baseline junto com mudança não relacionada; escreva no commit por que a UI mudou; revise diffs em tema claro, escuro e tamanhos relevantes; remova baselines de componentes deletados; evite snapshots gigantes de fluxos completos quando um componente pequeno resolve. Pense no baseline como contrato visual. Ele não é “arquivo gerado qualquer”. É uma decisão de produto capturada em imagem.\nRelação com previews e testes manuais Compose Preview continua útil para desenvolvimento rápido, documentação de estados e conversa com design. Screenshot testing adiciona automação e histórico. Teste manual continua necessário para gestos, acessibilidade real, navegação, performance e sensação de uso.\nUm bom fluxo usa os três. O desenvolvedor cria previews para os principais estados, promove os estados críticos para screenshot tests e ainda valida manualmente a experiência em dispositivo real antes de mudanças importantes. Para interfaces complexas, isso reduz retrabalho porque bugs visuais aparecem cedo, não depois do QA ou da publicação na Play Store.\nCuidados com acessibilidade Screenshot testing mostra pixels, mas não entende tudo sobre acessibilidade. Um texto pode parecer correto e ainda ter descrição ruim para leitor de tela. Um botão pode estar visível e não ter área de toque suficiente. Por isso, combine screenshots com validações semânticas do Compose UI Test quando possível.\ncomposeRule .onNodeWithContentDescription(\u0026#34;Confirmar pedido\u0026#34;) .assertIsDisplayed() .assertHasClickAction() Essa combinação protege tanto a aparência quanto a intenção da interface. Para times Android profissionais, esse é o ponto de maturidade: testar comportamento, estado, acessibilidade e regressão visual sem transformar o pipeline em uma parede lenta e frágil.\nPróximos passos Comece pequeno. Escolha um componente de alto reuso, crie dois ou três cenários, rode localmente, integre ao CI e observe o volume de ruído. Se a experiência for boa, expanda para telas críticas. Se os testes falharem por ambiente, estabilize o ambiente antes de aumentar cobertura.\nTambém vale comparar essa prática com outros ecossistemas. No frontend web, screenshot testing e visual regression já são comuns há anos; em times que usam Python para automação e QA, ferramentas visuais costumam aparecer junto de Playwright, Selenium ou pipelines de validação de interface. No Android com Kotlin, a vantagem é trazer a mesma disciplina para componentes Compose versionados, tipados e próximos do design system.\nTestes de screenshot não são uma bala de prata, mas resolvem uma categoria real de problema: regressões visuais pequenas que passam despercebidas até incomodarem usuários. Em projetos Kotlin modernos, especialmente com Jetpack Compose, eles funcionam melhor quando protegem componentes críticos, rodam em ambiente previsível e fazem parte de uma estratégia maior de qualidade junto com testes unitários, testes de UI, análise estática e revisão humana.\n","permalink":"https://kotlin.dev.br/blog/testes-screenshot-compose-kotlin-2026/","summary":"\u003cp\u003eTestes automatizados costumam entrar em projetos Android pela porta dos repositories, use cases e ViewModels. Isso é ótimo, mas deixa uma pergunta importante sem resposta: quem garante que a interface não quebrou visualmente? Um \u003ccode\u003eText\u003c/code\u003e truncado, um botão sem contraste, um card desalinhado ou um estado vazio com espaçamento errado podem passar por testes unitários perfeitos. Em apps escritos com \u003cstrong\u003eJetpack Compose e Kotlin\u003c/strong\u003e, os testes de screenshot ajudam a fechar essa lacuna.\u003c/p\u003e","title":"Testes de Screenshot no Compose com Kotlin em 2026 | Kotlin Brasil"},{"content":"DataStore Preferences é a alternativa moderna ao SharedPreferences para salvar configurações simples em apps Android com Kotlin. Ele resolve problemas comuns de leitura bloqueante, concorrência, callbacks difíceis de testar e integração fraca com arquitetura reativa. Em vez de chamar getString() espalhado pela aplicação, você expõe um Flow tipado, grava de forma assíncrona e mantém a camada de UI observando estado consistente.\nO caso de uso ideal é pequeno e frequente: tema escolhido, filtros de lista, flags de onboarding, último usuário selecionado, timestamp da última sincronização, preferências de notificação ou toggles de recurso. Para dados relacionais, listas grandes, busca, paginação ou histórico, use Room com Kotlin. Para sincronização confiável em background, combine com WorkManager. DataStore entra no meio: simples como preferências, mas com ergonomia de Kotlin moderno.\nQuando usar DataStore Preferences? Use DataStore Preferences quando você precisa persistir pares chave-valor pequenos e observar mudanças no app inteiro. Ele é especialmente útil quando a preferência afeta várias telas, porque o Flow permite que ViewModels reajam automaticamente.\nBons exemplos:\ntema claro, escuro ou seguindo o sistema; idioma selecionado dentro do app; filtro padrão de uma lista; ordenação escolhida pelo usuário; flag de onboarding concluído; token de paginação simples; data da última sincronização bem-sucedida; preferências locais de notificações. Evite DataStore para objetos grandes ou coleções que precisam de consulta. Se você quer filtrar tarefas por status, buscar por texto, relacionar entidades ou migrar esquema com várias tabelas, a escolha correta é Room. DataStore não é um banco de dados; ele é uma camada segura para preferências pequenas.\nDataStore Preferences vs Proto DataStore O Jetpack oferece duas formas principais de DataStore:\nOpção Melhor para Trade-off Preferences DataStore chaves simples, setup rápido, migração de SharedPreferences não tem schema formal Proto DataStore modelo tipado com schema e evolução controlada exige protobuf e mais configuração Para a maioria dos apps Android iniciando uma tela de configurações, Preferences DataStore é suficiente. Proto DataStore faz mais sentido quando a configuração vira um objeto de domínio importante, precisa de validação estrutural ou será compartilhada entre módulos com contrato explícito.\nNeste guia vamos focar em Preferences DataStore, porque ele cobre o caminho mais comum para substituir SharedPreferences sem criar complexidade prematura.\nDependências Adicione a dependência no módulo Android:\ndependencies { implementation(\u0026#34;androidx.datastore:datastore-preferences:1.1.1\u0026#34;) } Se o projeto já usa Compose, Coroutines e Flow, nenhuma mudança conceitual grande é necessária. DataStore combina naturalmente com ViewModel e collectAsStateWithLifecycle.\nCriando o DataStore O padrão mais comum é criar uma extensão no Context usando o delegate preferencesDataStore:\nimport android.content.Context import androidx.datastore.preferences.preferencesDataStore private val Context.userPreferencesDataStore by preferencesDataStore( name = \u0026#34;user_preferences\u0026#34;, ) O nome deve ser estável. Trocar esse nome cria outro arquivo de preferências, então trate como parte da persistência do app. Em projetos grandes, mantenha a extensão em um módulo de dados ou infraestrutura, não dentro de uma Activity.\nModelando preferências tipadas Mesmo usando Preferences DataStore, evite espalhar strings de chave pela aplicação. Defina chaves em um único lugar e exponha um modelo de domínio simples:\nenum class TemaApp { Sistema, Claro, Escuro, } data class UserPreferences( val tema: TemaApp = TemaApp.Sistema, val onboardingConcluido: Boolean = false, val ordemFavoritos: String = \u0026#34;recentes\u0026#34;, ) Agora crie as chaves:\nimport androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey private object PreferenceKeys { val Tema = stringPreferencesKey(\u0026#34;tema\u0026#34;) val OnboardingConcluido = booleanPreferencesKey(\u0026#34;onboarding_concluido\u0026#34;) val OrdemFavoritos = stringPreferencesKey(\u0026#34;ordem_favoritos\u0026#34;) } Essa pequena organização evita bugs bobos como usar theme em uma tela e tema em outra. Também deixa migrações e testes mais simples.\nRepository para leitura com Flow Crie uma classe responsável por transformar Preferences em um modelo da aplicação:\nimport androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.map import java.io.IOException class UserPreferencesRepository( private val dataStore: DataStore\u0026lt;Preferences\u0026gt;, ) { val preferences: Flow\u0026lt;UserPreferences\u0026gt; = dataStore.data .catch { exception -\u0026gt; if (exception is IOException) { emit(androidx.datastore.preferences.core.emptyPreferences()) } else { throw exception } } .map { prefs -\u0026gt; UserPreferences( tema = prefs[PreferenceKeys.Tema] ?.let { runCatching { TemaApp.valueOf(it) }.getOrNull() } ?: TemaApp.Sistema, onboardingConcluido = prefs[PreferenceKeys.OnboardingConcluido] ?: false, ordemFavoritos = prefs[PreferenceKeys.OrdemFavoritos] ?: \u0026#34;recentes\u0026#34;, ) } } O catch acima trata erro de leitura do arquivo como fallback para preferências vazias. Não engula qualquer exceção. Se o problema for programação incorreta, corrupção não tratada ou outro erro inesperado, deixar a exceção aparecer ajuda a corrigir o bug.\nGravando preferências Para escrever, use edit. A operação é suspensa e transacional para o arquivo de preferências:\nimport androidx.datastore.preferences.core.edit suspend fun definirTema(tema: TemaApp) { dataStore.edit { prefs -\u0026gt; prefs[PreferenceKeys.Tema] = tema.name } } suspend fun concluirOnboarding() { dataStore.edit { prefs -\u0026gt; prefs[PreferenceKeys.OnboardingConcluido] = true } } suspend fun definirOrdemFavoritos(ordem: String) { dataStore.edit { prefs -\u0026gt; prefs[PreferenceKeys.OrdemFavoritos] = ordem } } Não faça escrita direta na UI. A tela chama um método do ViewModel, o ViewModel chama o repository e o estado volta pelo Flow. Esse fluxo unidirecional evita inconsistência entre “o botão foi tocado” e “a preferência realmente foi persistida”.\nUsando no ViewModel No ViewModel, exponha o fluxo como estado de tela:\nclass SettingsViewModel( private val repository: UserPreferencesRepository, ) : ViewModel() { val uiState: StateFlow\u0026lt;UserPreferences\u0026gt; = repository.preferences .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = UserPreferences(), ) fun selecionarTema(tema: TemaApp) { viewModelScope.launch { repository.definirTema(tema) } } } Se você já usa MVVM com Kotlin, esse desenho deve parecer familiar: a UI observa estado, o ViewModel expõe ações e o repository cuida da persistência.\nConsumindo em Compose Em Jetpack Compose, a tela pode observar o estado com lifecycle-aware collection:\n@Composable fun SettingsScreen( viewModel: SettingsViewModel, ) { val preferences by viewModel.uiState.collectAsStateWithLifecycle() Column { Text(\u0026#34;Tema\u0026#34;) TemaApp.entries.forEach { tema -\u0026gt; Row( modifier = Modifier.clickable { viewModel.selecionarTema(tema) }, ) { RadioButton( selected = preferences.tema == tema, onClick = { viewModel.selecionarTema(tema) }, ) Text(text = tema.name) } } } } Para aprofundar a camada visual, veja também o guia de Jetpack Compose e os tutoriais de layouts. DataStore não deve conhecer Compose; ele apenas fornece estado.\nMigração de SharedPreferences Se o app já usa SharedPreferences, DataStore oferece migração. Isso é importante porque trocar a implementação sem migrar pode resetar tema, filtros e flags do usuário.\nprivate val Context.userPreferencesDataStore by preferencesDataStore( name = \u0026#34;user_preferences\u0026#34;, produceMigrations = { context -\u0026gt; listOf( SharedPreferencesMigration( context = context, sharedPreferencesName = \u0026#34;legacy_user_preferences\u0026#34;, ), ) }, ) Antes de remover o código antigo, valide em um build com dados reais ou fixture de QA. A migração deve preservar os nomes das chaves relevantes ou mapear valores quando o formato mudou. Se antes você salvava \u0026quot;dark\u0026quot; e agora usa TemaApp.Escuro.name, trate essa conversão explicitamente.\nDataStore em arquitetura offline-first Em apps offline-first, DataStore costuma guardar metadados pequenos enquanto Room guarda o estado principal. Um exemplo comum:\nRoom: entidades, filas pendentes, dados exibidos na tela; DataStore: último sync bem-sucedido, filtro escolhido, usuário ativo, feature flag local; WorkManager: execução de sincronização quando houver rede; Repository: regra que combina tudo isso. Esse desenho evita dois extremos ruins: colocar preferências simples no banco só por formalidade ou enfiar dados de produto dentro de DataStore porque é mais rápido de começar. Cada ferramenta resolve um problema.\nSe a sua tela offline-first precisa mostrar “última atualização: 10:32”, DataStore pode guardar esse timestamp. Se precisa listar 300 pedidos pendentes, use Room.\nTestes O repository de DataStore é fácil de testar quando você injeta DataStore\u0026lt;Preferences\u0026gt; em vez de buscar Context diretamente dentro da classe. Em testes instrumentados ou Robolectric, crie um arquivo temporário e valide leitura/escrita.\nO que vale testar:\nvalor padrão quando não existe preferência salva; escrita de tema atualiza o fluxo observado; valores antigos de SharedPreferences são migrados; enum inválido cai para valor seguro; erro de leitura esperado não derruba a tela; ViewModel chama o repository em uma ação de UI. Para testes unitários de lógica ao redor, combine com JUnit 5 e MockK. Para fluxos, Turbine também é uma boa ferramenta, especialmente quando você precisa validar sequência de emissões.\nErros comuns O primeiro erro é usar DataStore como banco. Quando preferências começam a virar JSON grande, lista serializada ou mapa complexo, provavelmente você está escondendo uma entidade que deveria estar no Room.\nO segundo erro é ler DataStore de forma pontual em todo lugar. O modelo idiomático é observar Flow e transformar em estado. Se cada tela cria sua própria leitura avulsa, o app fica difícil de testar.\nO terceiro erro é salvar strings livres sem fallback. Enums mudam, valores antigos continuam no dispositivo e usuários atualizam de versões antigas. Sempre trate valor desconhecido.\nO quarto erro é esquecer que preferências também fazem parte da experiência. Resetar tema, idioma, onboarding ou filtros em uma atualização passa sensação de app quebrado. Migração deve entrar no checklist de release.\nChecklist prático Antes de usar DataStore Preferences em produção, confirme:\nas chaves ficam centralizadas; o repository expõe um modelo tipado; a UI observa estado via ViewModel; valores padrão são explícitos; enums têm fallback seguro; SharedPreferences legado foi migrado quando necessário; dados grandes continuam no Room; testes cobrem leitura, escrita e migração. Conclusão DataStore Preferences é uma melhoria direta para apps Android Kotlin que ainda dependem de SharedPreferences. Ele combina persistência simples, coroutines, Flow e uma API mais segura para arquitetura moderna. O ganho não é apenas técnico: preferências reativas deixam a UI consistente, reduzem leituras bloqueantes e tornam testes mais previsíveis.\nUse DataStore para configurações pequenas, Room para dados estruturados e WorkManager para trabalho persistente em background. Essa combinação forma uma base forte para apps Android reais em 2026: responsivos, offline-aware e fáceis de evoluir. Para quem está montando portfólio, uma tela de configurações com DataStore bem organizado mostra maturidade além do CRUD básico.\n","permalink":"https://kotlin.dev.br/tutoriais/datastore-preferences-kotlin/","summary":"\u003cp\u003eDataStore Preferences é a alternativa moderna ao \u003ccode\u003eSharedPreferences\u003c/code\u003e para salvar configurações simples em apps Android com Kotlin. Ele resolve problemas comuns de leitura bloqueante, concorrência, callbacks difíceis de testar e integração fraca com arquitetura reativa. Em vez de chamar \u003ccode\u003egetString()\u003c/code\u003e espalhado pela aplicação, você expõe um \u003ccode\u003eFlow\u003c/code\u003e tipado, grava de forma assíncrona e mantém a camada de UI observando estado consistente.\u003c/p\u003e\n\u003cp\u003eO caso de uso ideal é pequeno e frequente: tema escolhido, filtros de lista, flags de onboarding, último usuário selecionado, timestamp da última sincronização, preferências de notificação ou toggles de recurso. Para dados relacionais, listas grandes, busca, paginação ou histórico, use \u003ca href=\"/tutoriais/kotlin-room-database-tutorial/\"\u003eRoom com Kotlin\u003c/a\u003e. Para sincronização confiável em background, combine com \u003ca href=\"/blog/workmanager-kotlin-android-2026/\"\u003eWorkManager\u003c/a\u003e. DataStore entra no meio: simples como preferências, mas com ergonomia de Kotlin moderno.\u003c/p\u003e","title":"DataStore Preferences com Kotlin: Guia Android em 2026 | Kotlin Brasil"},{"content":"Escolher backend para um app Kotlin parece simples no começo: você precisa de login, banco de dados, storage e talvez notificações push. Mas, quando o projeto cresce, a decisão entre Firebase, Supabase ou um backend próprio em Kotlin começa a afetar arquitetura, custo, testes, privacidade, offline-first e até a facilidade de contratar devs para manter o produto. A decisão também precisa conversar com segurança de dados locais no Android, porque tokens, cache e filas offline continuam no dispositivo mesmo quando o backend é gerenciado.\nEm 2026, essa escolha ficou ainda mais interessante. O Firebase continua muito forte no ecossistema Android, especialmente para MVPs e produtos com push, analytics e integração com Google Cloud. O Supabase cresceu como alternativa open source com PostgreSQL, autenticação, storage e APIs geradas a partir do banco. E, ao mesmo tempo, Kotlin no backend com Ktor ou Spring Boot virou uma opção madura para times que querem controle total.\nEste guia ajuda você a decidir com critérios práticos, sem transformar a escolha em torcida por ferramenta.\nO que comparar antes de escolher Antes de abrir o console de qualquer plataforma, responda algumas perguntas:\nO app precisa funcionar bem offline? O modelo de dados é simples ou tem muitas regras de negócio? Você precisa de relatórios SQL, joins e consultas analíticas? O time domina mais Android/Kotlin, SQL/PostgreSQL ou infraestrutura cloud? Existe risco de custo crescer rápido com leitura, escrita ou storage? O produto precisa ser multiplataforma com Kotlin Multiplatform? As regras de segurança conseguem ser expressas no próprio backend da plataforma? A resposta costuma mostrar que não existe “melhor backend universal”. Existe o backend mais coerente para o momento do produto.\nQuando Firebase faz mais sentido O Firebase é uma escolha muito produtiva para apps Kotlin e Android quando você quer velocidade inicial, integração com recursos mobile e pouco trabalho de infraestrutura.\nEle costuma fazer sentido quando o projeto precisa de:\nautenticação rápida com provedores populares; push notifications com Firebase Cloud Messaging; analytics, crash reporting e remote config integrados; sincronização em tempo real com Firestore ou Realtime Database; hosting e funções serverless simples; uma esteira mobile bem próxima do ecossistema Google. Para um app Android puro, a ergonomia é excelente. A documentação conversa diretamente com Android Studio, Gradle, Google Play Services e o ciclo de vida mobile. Se você está criando um MVP, protótipo validável ou produto com poucos relacionamentos complexos, Firebase reduz muita fricção.\nO ponto de atenção é que o Firebase pede disciplina. Firestore não é PostgreSQL. Modelar dados como se fosse um banco relacional pode gerar consultas ruins, duplicação sem controle e regras de segurança difíceis de revisar. Também vale acompanhar custo desde cedo, principalmente em telas que fazem muitas leituras automáticas.\nQuando Supabase faz mais sentido Supabase é atraente quando você quer uma experiência parecida com Backend as a Service, mas com PostgreSQL no centro. Para muitos produtos, isso muda bastante o jogo.\nEle costuma fazer sentido quando o app precisa de:\nconsultas relacionais mais naturais; dashboards, relatórios e SQL direto; constraints, views, triggers e funções no banco; portabilidade maior por usar tecnologias abertas; autenticação e storage prontos sem abandonar PostgreSQL; uma ponte mais simples entre app mobile, painel administrativo e automações. Para times brasileiros que já têm experiência com SQL, Supabase pode ser mais fácil de raciocinar do que Firestore. Tabelas, chaves estrangeiras, índices e políticas de acesso via Row Level Security são conceitos fortes, mas previsíveis.\nO cuidado principal é não jogar regra de negócio sensível em lugares demais. Se parte da lógica fica no app, parte em policies, parte em Edge Functions e parte em triggers, a manutenção pode ficar confusa. Documente as fronteiras desde o começo.\nE backend próprio em Kotlin? Um backend próprio em Kotlin com Ktor ou Spring Boot vale a pena quando a regra de negócio vira o coração do produto. Essa opção exige mais trabalho inicial, mas entrega controle.\nEla faz sentido quando você precisa de:\nintegrações complexas com ERPs, gateways, filas ou sistemas legados; regras de autorização difíceis de expressar em BaaS; auditoria, logs e observabilidade customizada; processamento assíncrono mais sofisticado; domínio rico, com validações e workflows importantes; independência maior de uma plataforma específica. O custo é claro: você precisa operar deploy, banco, migrations, logs, métricas, backups e segurança. Para um time pequeno, isso pode ser peso demais no início. Para um produto que já validou demanda, pode ser o caminho mais sustentável.\nSe esse for seu caso, revise também nosso conteúdo sobre Kotlin server-side em 2026, monólito modular com Kotlin e Spring e observabilidade para aplicações Kotlin.\nCritérios práticos por tipo de app App de conteúdo, comunidade ou MVP simples Firebase tende a ganhar pela velocidade. Auth, push, analytics e remote config resolvem muita coisa sem criar um backend completo. Supabase também funciona bem, especialmente se houver painel administrativo e relatórios.\nApp com dados relacionais fortes Supabase ou backend próprio tendem a ser mais naturais. Exemplos: marketplace com vendedores, pedidos, pagamentos, repasses, disputas e relatórios; SaaS com organizações, usuários, permissões e planos; produto B2B com dashboards.\nApp offline-first Firebase pode ajudar com sincronização e cache, mas não elimina arquitetura local. Em apps sérios, você ainda vai pensar em Room, filas de sincronização, conflitos e estados intermediários. Vale ler o guia de Android offline-first com Kotlin e o artigo sobre Room no Kotlin Multiplatform.\nApp multiplataforma com KMP Supabase e backend próprio costumam ser mais previsíveis para compartilhar camada de rede e modelos no commonMain. Firebase pode funcionar, mas a integração multiplataforma exige mais atenção aos SDKs disponíveis, APIs específicas por plataforma e wrappers.\nProduto com IA, agentes ou automações Backend próprio em Kotlin ou Supabase com funções pode ser melhor se você precisa controlar filas, logs, custos, chamadas a modelos e ferramentas. Firebase ainda pode entrar para auth, analytics e push, mas talvez não deva concentrar toda a lógica.\nExemplo de matriz de decisão Use uma matriz simples antes de decidir:\nCritério Firebase Supabase Backend Kotlin Velocidade para MVP Android Alta Alta Média Consultas relacionais Baixa/Média Alta Alta Push e analytics mobile Alta Média Baixa/Média Controle de regra de negócio Médio Médio/Alto Alto Operação inicial Baixa Baixa/Média Alta Portabilidade Média Alta Alta Melhor para KMP Médio Alto Alto A matriz não decide sozinha, mas força uma conversa objetiva. Se o projeto depende de push e analytics, Firebase ganha pontos. Se depende de SQL e relatórios, Supabase ganha pontos. Se depende de regra de negócio própria, backend Kotlin ganha pontos.\nErros comuns na escolha 1. Escolher só pelo hype Ferramenta popular não resolve arquitetura ruim. Um app pequeno pode ficar ótimo com Firebase. Um produto relacional pode sofrer muito com Firestore. Um backend próprio pode ser excesso para validar uma ideia simples.\n2. Ignorar custo por padrão de uso Em BaaS, custo não cresce apenas por usuário. Cresce por leitura, escrita, storage, bandwidth, funções e padrões de sincronização. Uma tela que recarrega dados demais pode ficar cara antes do produto ficar grande.\n3. Colocar regra crítica apenas no app Nunca confie regra sensível apenas no cliente Android. Preço, permissão, assinatura, saldo, limite, ownership e validações importantes precisam de enforcement no servidor, nas policies ou no banco.\n4. Não planejar migração Mesmo que você escolha Firebase ou Supabase, desenhe uma camada de repositório no app. Evite espalhar SDK diretamente por todas as telas. Isso facilita testes, troca de implementação e evolução para backend próprio.\nUm caminho seguro para começar Para a maioria dos times pequenos, uma abordagem pragmática funciona bem:\nComece com Firebase se o app é fortemente Android/mobile e precisa validar rápido. Comece com Supabase se SQL, painel administrativo e relatórios já são importantes. Comece com backend Kotlin se a regra de negócio é o diferencial do produto. Em qualquer caso, isole acesso a dados atrás de interfaces e repositórios. Meça custo, latência, erros e retenção desde o primeiro deploy. Um exemplo simples de fronteira no app:\ninterface UsuarioRepository { suspend fun usuarioAtual(): Usuario? suspend fun atualizarPerfil(perfil: PerfilUsuario) } class FirebaseUsuarioRepository(/* sdk */) : UsuarioRepository { override suspend fun usuarioAtual(): Usuario? { // implementação usando Firebase Auth/Firestore TODO() } override suspend fun atualizarPerfil(perfil: PerfilUsuario) { // validação local simples + escrita remota TODO() } } A tela não precisa saber se o dado vem de Firebase, Supabase ou Ktor. Ela conversa com o contrato. Essa pequena disciplina evita acoplamento prematuro.\nConclusão Se você está criando um app Kotlin em 2026, a pergunta não é “Firebase ou Supabase?”. A pergunta certa é: qual backend reduz risco agora sem prender o produto em uma arquitetura frágil depois?\nFirebase é excelente para velocidade mobile e integração Android. Supabase brilha quando PostgreSQL, SQL e relatórios importam desde cedo. Backend próprio em Kotlin é o caminho quando o domínio do produto precisa de controle, observabilidade e regras ricas.\nEscolha com base no tipo de app, proteja sua arquitetura com repositórios e revise a decisão quando o produto mudar de fase. Backend bom é aquele que deixa o time entregar valor sem esconder dívidas que explodem em produção.\n","permalink":"https://kotlin.dev.br/blog/kotlin-firebase-supabase-backend-mobile-2026/","summary":"\u003cp\u003eEscolher backend para um app Kotlin parece simples no começo: você precisa de login, banco de dados, storage e talvez notificações push. Mas, quando o projeto cresce, a decisão entre \u003cstrong\u003eFirebase\u003c/strong\u003e, \u003cstrong\u003eSupabase\u003c/strong\u003e ou um backend próprio em Kotlin começa a afetar arquitetura, custo, testes, privacidade, offline-first e até a facilidade de contratar devs para manter o produto. A decisão também precisa conversar com \u003ca href=\"/blog/seguranca-dados-locais-android-kotlin-2026/\"\u003esegurança de dados locais no Android\u003c/a\u003e, porque tokens, cache e filas offline continuam no dispositivo mesmo quando o backend é gerenciado.\u003c/p\u003e","title":"Kotlin com Firebase ou Supabase: Guia para Apps em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaVaga remota para Engenheiro(a) Senior de Middleware na Partner One, com atuação no Brasil. A posição envolve plataformas de mensageria, integração, infraestrutura em nuvem e observabilidade.\nResponsabilidadesProjetar, manter e evoluir soluções de middleware e mensageria.Trabalhar com RabbitMQ, Redis e Azure Service Bus.Apoiar ambientes em Kubernetes com foco em confiabilidade e escalabilidade.Implementar e acompanhar métricas, logs e tracing com Prometheus, Grafana e OpenTelemetry.Contribuir com automação e infraestrutura como código usando Terraform, Bicep e Ansible.Atuar com segurança, controle de acesso, RBAC, Managed Identity e TLS.RequisitosExperiência senior em engenharia de middleware, integração ou plataformas distribuídas.Conhecimento em formatos e contratos de dados como JSON, Avro e Protobuf.Experiência com mensageria, filas, eventos e comunicação entre serviços.Vivência com Kubernetes e práticas de operação em produção.Conhecimento em observabilidade e troubleshooting de sistemas distribuídos.DiferenciaisExperiência com XDS.Vivência em ambientes Azure.Experiência com automação de infraestrutura e políticas de segurança em escala.Modelo de trabalhoTrabalho remoto para profissionais localizados no Brasil.\n","permalink":"https://kotlin.dev.br/vagas/uap4twifk3pdqhbk-partner-one-engenheiro-a-senior-de-middleware/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga remota para Engenheiro(a) Senior de Middleware na Partner One, com atuação no Brasil. A posição envolve plataformas de mensageria, integração, infraestrutura em nuvem e observabilidade.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eProjetar, manter e evoluir soluções de middleware e mensageria.\u003c/li\u003e\u003cli\u003eTrabalhar com RabbitMQ, Redis e Azure Service Bus.\u003c/li\u003e\u003cli\u003eApoiar ambientes em Kubernetes com foco em confiabilidade e escalabilidade.\u003c/li\u003e\u003cli\u003eImplementar e acompanhar métricas, logs e tracing com Prometheus, Grafana e OpenTelemetry.\u003c/li\u003e\u003cli\u003eContribuir com automação e infraestrutura como código usando Terraform, Bicep e Ansible.\u003c/li\u003e\u003cli\u003eAtuar com segurança, controle de acesso, RBAC, Managed Identity e TLS.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência senior em engenharia de middleware, integração ou plataformas distribuídas.\u003c/li\u003e\u003cli\u003eConhecimento em formatos e contratos de dados como JSON, Avro e Protobuf.\u003c/li\u003e\u003cli\u003eExperiência com mensageria, filas, eventos e comunicação entre serviços.\u003c/li\u003e\u003cli\u003eVivência com Kubernetes e práticas de operação em produção.\u003c/li\u003e\u003cli\u003eConhecimento em observabilidade e troubleshooting de sistemas distribuídos.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com XDS.\u003c/li\u003e\u003cli\u003eVivência em ambientes Azure.\u003c/li\u003e\u003cli\u003eExperiência com automação de infraestrutura e políticas de segurança em escala.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eTrabalho remoto para profissionais localizados no Brasil.\u003c/p\u003e","title":"Engenheiro(a) Senior de Middleware"},{"content":"Redis aparece com frequência em stacks backend Kotlin porque resolve problemas que banco relacional, API REST e fila tradicional não deveriam resolver sozinhos. Cache de leitura, sessão distribuída, rate limiting, locks curtos, contadores, rankings e pub/sub simples são exemplos comuns. Para quem trabalha com Kotlin para backend, entender Redis ajuda a desenhar APIs mais rápidas sem transformar o banco principal em gargalo.\nO ponto importante é não tratar Redis como um banco mágico. Ele é rápido porque mantém dados em memória e oferece estruturas especializadas. Isso traz benefícios enormes, mas também exige disciplina com TTL, invalidação, observabilidade, serialização e fallback. Um cache errado pode entregar dado velho; uma chave sem expiração pode crescer para sempre; um rate limiter mal modelado pode bloquear usuários legítimos.\nEste guia mostra quando usar Redis em aplicações Kotlin, como integrar com Spring Boot e Ktor, quais padrões são seguros em produção e como esse conhecimento aparece em vagas backend no Brasil.\nQuando Redis faz sentido em Kotlin Redis é útil quando existe uma operação frequente, curta e sensível a latência. Se cada request precisa consultar uma tabela grande, chamar um serviço externo ou recalcular uma resposta estável por alguns minutos, cache pode reduzir custo e melhorar experiência. Em aplicações Kotlin, isso aparece em APIs de catálogo, permissões, feature flags, perfis, tokens, dashboards, antifraude leve e agregações de leitura.\nCasos comuns:\nCache de leitura: guardar respostas calculadas por alguns segundos ou minutos. Sessões e tokens: manter estado curto compartilhado entre múltiplas instâncias. Rate limiting: limitar chamadas por usuário, IP, rota ou chave de API. Locks curtos: evitar execução simultânea de uma rotina crítica. Contadores e rankings: incrementar métricas ou scores com baixa latência. Pub/Sub simples: notificar instâncias sobre eventos leves, sem exigir Kafka. Nem todo cache precisa de Redis. Um cache em memória local pode ser suficiente quando a aplicação roda em uma única instância ou quando não importa que cada instância tenha uma cópia diferente. Redis entra quando o estado precisa ser compartilhado, quando o volume é maior ou quando você precisa de operações atômicas entre processos.\nDependências com Spring Boot No Spring Boot, a integração mais comum usa Spring Data Redis com Lettuce. Em Kotlin, a configuração fica parecida com qualquer projeto JVM:\ndependencies { implementation(\u0026#34;org.springframework.boot:spring-boot-starter-data-redis\u0026#34;) implementation(\u0026#34;com.fasterxml.jackson.module:jackson-module-kotlin\u0026#34;) } Um serviço de cache simples pode usar StringRedisTemplate para valores textuais:\n@Service class ProdutoCacheService( private val redis: StringRedisTemplate, private val objectMapper: ObjectMapper, ) { private val ttl = Duration.ofMinutes(5) fun salvarResumo(produto: ProdutoResumo) { val chave = \u0026#34;produto:${produto.id}:resumo\u0026#34; val json = objectMapper.writeValueAsString(produto) redis.opsForValue().set(chave, json, ttl) } fun buscarResumo(id: Long): ProdutoResumo? { val json = redis.opsForValue().get(\u0026#34;produto:$id:resumo\u0026#34;) ?: return null return objectMapper.readValue(json, ProdutoResumo::class.java) } } Esse exemplo parece simples, mas já tem uma decisão importante: a chave carrega namespace, identificador e tipo de dado. Evite chaves genéricas como produto:123 se diferentes partes do sistema podem guardar formatos distintos. Prefira nomes explícitos e previsíveis.\nCache-aside: o padrão mais seguro para começar O padrão mais comum é cache-aside. A aplicação tenta ler do Redis; se não encontrar, busca no banco, grava no cache e devolve a resposta. Em Kotlin, a ideia pode ficar assim:\nclass ProdutoService( private val repository: ProdutoRepository, private val cache: ProdutoCacheService, ) { fun buscarResumo(id: Long): ProdutoResumo { cache.buscarResumo(id)?.let { return it } val produto = repository.findById(id) .orElseThrow { ProdutoNaoEncontradoException(id) } .toResumo() cache.salvarResumo(produto) return produto } } O cuidado está na invalidação. Se o produto muda, apague ou atualize a chave relacionada. Para dados que toleram pequena defasagem, TTL curto costuma ser mais simples do que tentar invalidar todas as variações possíveis. Para dados críticos, como saldo financeiro ou permissão de segurança, cache precisa ser tratado com muito mais rigor ou evitado.\nRedis com Ktor e coroutines No Ktor, você pode usar clientes assíncronos compatíveis com coroutines ou adaptar chamadas bloqueantes com cuidado. O princípio é o mesmo do guia de Ktor: não bloquear o event loop do servidor.\nUm wrapper simples pode expor funções suspensas:\nclass RedisCache( private val commands: RedisAsyncCommands\u0026lt;String, String\u0026gt;, ) { suspend fun get(chave: String): String? = commands.get(chave).await() suspend fun set(chave: String, valor: String, ttlSegundos: Long) { commands.setex(chave, ttlSegundos, valor).await() } } Em rotas Ktor, mantenha Redis atrás de um serviço. A rota deve validar entrada e montar resposta; a decisão de cache pertence à camada de aplicação. Isso evita espalhar nomes de chaves, TTLs e serialização por controllers.\nRate limiting com operações atômicas Redis é muito usado para rate limiting porque incrementos são rápidos e atômicos. Um modelo básico por usuário e janela de tempo pode usar INCR com expiração:\nclass RateLimiter( private val redis: StringRedisTemplate, ) { fun permitir(usuarioId: String, limite: Long): Boolean { val minutoAtual = Instant.now().epochSecond / 60 val chave = \u0026#34;rate:user:$usuarioId:$minutoAtual\u0026#34; val total = redis.opsForValue().increment(chave) ?: 1 if (total == 1L) { redis.expire(chave, Duration.ofMinutes(2)) } return total \u0026lt;= limite } } Para produção de alto volume, Lua scripts ou algoritmos como sliding window podem ser melhores. Mesmo assim, o exemplo mostra o raciocínio central: cada janela vira uma chave temporária, o Redis garante incremento atômico e o TTL limpa dados antigos. Se quiser comparar a mesma decisão em outro stack backend, o guia de rate limiting em APIs Go ajuda a separar algoritmo, armazenamento e política de abuso sem prender o raciocínio ao framework.\nSessões distribuídas e tokens curtos Quando uma aplicação roda em várias instâncias, sessão em memória local vira problema. Redis permite guardar sessão curta com TTL e compartilhar o estado entre instâncias. Isso é útil para login web tradicional, fluxos de OAuth, códigos temporários, confirmação de e-mail e carrinhos efêmeros.\nMas cuidado: sessão em Redis não substitui modelagem de segurança. Nunca guarde senha, segredo permanente ou dado sensível sem necessidade. Defina TTL explícito, invalide no logout quando o fluxo exigir e registre métricas de criação, expiração e falha. Se o Redis ficar indisponível, a aplicação deve responder de forma previsível, não entrar em loop de erro.\nFilas leves não são mensageria completa Redis tem listas, streams e pub/sub. Isso permite montar filas pequenas e notificações internas. Para tarefas simples, pode funcionar bem. Porém, se você precisa de reprocessamento robusto, dead letter queue, retenção longa, múltiplos consumidores independentes e auditoria forte, leia também o guia de Kotlin com Kafka e RabbitMQ.\nA regra prática é simples: Redis serve para coordenação leve e baixa latência. Kafka, RabbitMQ e SQS servem melhor para mensageria operacional crítica. Usar Redis como broker principal de tudo costuma criar dívida técnica quando o produto cresce.\nBoas práticas de produção Antes de colocar Redis no caminho crítico, defina alguns padrões:\nUse TTL em quase todas as chaves, especialmente cache e sessão. Padronize nomes de chaves com prefixo de domínio e versão quando necessário. Monitore hit rate, latência, memória, evictions, conexões e erros. Não faça cache de dados que precisam ser perfeitamente atuais sem estratégia clara. Trate indisponibilidade com fallback, timeout curto e logs úteis. Evite valores enormes; Redis não deve virar depósito de documentos gigantes. Teste serialização e compatibilidade quando mudar o formato dos dados. Também vale separar cache de contrato público. O formato salvo no Redis é detalhe interno. Se uma mudança de código exige limpar chaves antigas, planeje deploy com versão de chave, TTL baixo ou limpeza explícita.\nComo isso ajuda na carreira Kotlin Vagas backend Kotlin frequentemente pedem Spring Boot, APIs REST, PostgreSQL, Kafka, Docker, Kubernetes, AWS e Redis. Saber explicar Redis mostra maturidade porque o assunto conecta performance, arquitetura, operação e experiência do usuário. Não basta dizer “coloquei cache”; o diferencial é explicar o que foi cacheado, por quanto tempo, como invalidou, como mediu hit rate e o que acontece quando Redis cai.\nPara estudar, construa uma API pequena com Kotlin e PostgreSQL, adicione cache-aside em uma consulta, implemente rate limiting por usuário e coloque métricas básicas. Depois compare o comportamento com e sem cache. Esse exercício vale mais do que decorar comandos isolados.\nConclusão Redis combina muito bem com Kotlin backend quando usado com propósito: acelerar leituras, compartilhar estado curto, limitar abuso e coordenar operações leves. A linguagem ajuda com modelos tipados, serviços pequenos e integração com frameworks maduros como Spring Boot e Ktor.\nO risco está no excesso de confiança. Cache não corrige consulta mal modelada, sessão distribuída não elimina cuidado de segurança e pub/sub simples não substitui uma plataforma de mensageria quando o produto exige garantias. Comece com casos claros, TTL curto, observabilidade desde o primeiro deploy e fallback previsível. Assim, Redis deixa de ser “mais uma dependência” e vira uma ferramenta prática para entregar backend Kotlin mais rápido e resiliente.\n","permalink":"https://kotlin.dev.br/blog/kotlin-redis-cache-sessoes-2026/","summary":"\u003cp\u003eRedis aparece com frequência em stacks backend Kotlin porque resolve problemas que banco relacional, API REST e fila tradicional não deveriam resolver sozinhos. Cache de leitura, sessão distribuída, rate limiting, locks curtos, contadores, rankings e pub/sub simples são exemplos comuns. Para quem trabalha com \u003ca href=\"/guias/kotlin-para-backend/\"\u003eKotlin para backend\u003c/a\u003e, entender Redis ajuda a desenhar APIs mais rápidas sem transformar o banco principal em gargalo.\u003c/p\u003e\n\u003cp\u003eO ponto importante é não tratar Redis como um banco mágico. Ele é rápido porque mantém dados em memória e oferece estruturas especializadas. Isso traz benefícios enormes, mas também exige disciplina com TTL, invalidação, observabilidade, serialização e fallback. Um cache errado pode entregar dado velho; uma chave sem expiração pode crescer para sempre; um rate limiter mal modelado pode bloquear usuários legítimos.\u003c/p\u003e","title":"Kotlin com Redis: Cache, Sessões e Rate Limiting em 2026 | Kotlin Brasil"},{"content":"GraphQL aparece cada vez mais em vagas Android porque resolve um problema real de produto: telas mobile raramente precisam exatamente do mesmo payload que o backend REST já expõe. Uma home pode precisar de nome do usuário, saldo resumido, banners, atalhos e notificações; uma tela de detalhe pode misturar informações de catálogo, preço, disponibilidade e recomendações. Quando cada tela depende de várias chamadas REST, o app fica mais sensível a latência, versionamento e campos desnecessários.\nCom Kotlin no Android, o caminho mais comum para consumir GraphQL é usar Apollo Kotlin. A biblioteca gera modelos tipados a partir do schema, integra bem com coroutines, pode expor resultados como Flow e oferece cache normalizado para cenários em que múltiplas queries compartilham os mesmos objetos. Isso combina com arquiteturas modernas baseadas em MVVM, Clean Architecture e apps offline-first.\nEste guia mostra quando GraphQL faz sentido no Android, como estruturar o client com Kotlin, quais cuidados tomar com cache e erros, e como transformar esse conhecimento em diferencial para projetos e entrevistas em 2026.\nQuando GraphQL vale a pena no Android? GraphQL não é automaticamente melhor que REST. Para uma API pequena, estável e com endpoints bem desenhados, REST continua simples, barato e suficiente. O ganho do GraphQL aparece quando o app tem telas ricas, múltiplos consumidores, evolução frequente de produto ou necessidade de compor dados sem criar um endpoint novo para cada variação de tela.\nNo Android, ele costuma valer a pena quando:\numa mesma entidade aparece em várias telas com subconjuntos diferentes de campos; o app precisa reduzir chamadas em redes móveis instáveis; o backend atende Android, iOS, web e parceiros externos; o time quer tipagem forte entre contrato e client; features mudam rápido e exigem evolução gradual de campos; a empresa já usa GraphQL em BFFs, gateways ou federação. O ponto principal é tratar GraphQL como contrato de produto, não como moda de API. Se o backend expõe um schema confuso, sem paginação, sem política de erro e sem observabilidade, o app Android só troca um tipo de acoplamento por outro.\nConfigurando Apollo Kotlin no Gradle Em um projeto Android moderno, o Apollo entra pelo build.gradle.kts. A versão exata deve acompanhar a documentação oficial e o padrão do seu time, mas a estrutura é parecida:\nplugins { id(\u0026#34;com.android.application\u0026#34;) kotlin(\u0026#34;android\u0026#34;) id(\u0026#34;com.apollographql.apollo\u0026#34;) version \u0026#34;4.0.0\u0026#34; } apollo { service(\u0026#34;api\u0026#34;) { packageName.set(\u0026#34;br.dev.kotlin.app.graphql\u0026#34;) schemaFile.set(file(\u0026#34;src/main/graphql/schema.graphqls\u0026#34;)) } } As queries ficam em arquivos .graphql, normalmente em src/main/graphql. Por exemplo:\nquery PerfilResumo($id: ID!) { usuario(id: $id) { id nome avatarUrl plano } } O Apollo gera classes Kotlin para essa operação. Isso reduz erros comuns de string solta, nome de campo digitado errado e parsing manual de JSON. Quando o schema muda, o build acusa incompatibilidades antes de o app chegar ao QA.\nCriando um ApolloClient idiomático O client deve ser configurado em um ponto central, normalmente via injeção de dependência. Se você usa Hilt, Koin ou injeção manual, a ideia é a mesma: criar uma instância reaproveitável, com endpoint, headers, interceptors e política de cache.\nfun criarApolloClient(tokenProvider: TokenProvider): ApolloClient { return ApolloClient.Builder() .serverUrl(\u0026#34;https://api.exemplo.com/graphql\u0026#34;) .addHttpHeader(\u0026#34;Accept\u0026#34;, \u0026#34;application/json\u0026#34;) .addInterceptor { request, chain -\u0026gt; val token = tokenProvider.tokenAtual() val autenticada = request.newBuilder() .addHttpHeader(\u0026#34;Authorization\u0026#34;, \u0026#34;Bearer $token\u0026#34;) .build() chain.proceed(autenticada) } .build() } Em produção, não deixe token espalhado em ViewModel, tela Compose ou helper global. O client pertence à camada de dados. A UI deveria depender de casos de uso ou repositories que já devolvem estado de tela pronto.\nRepository com coroutines e Flow Uma chamada simples pode usar suspend:\nclass PerfilRepository( private val apolloClient: ApolloClient, ) { suspend fun buscarPerfil(id: String): PerfilResumo { val response = apolloClient .query(PerfilResumoQuery(id = id)) .execute() val usuario = response.data?.usuario ?: throw IllegalStateException(\u0026#34;Perfil não encontrado\u0026#34;) return PerfilResumo( id = usuario.id, nome = usuario.nome, avatarUrl = usuario.avatarUrl, plano = usuario.plano, ) } } Para telas que precisam reagir a cache, refresh ou mudanças locais, Flow costuma deixar o desenho mais claro. A ViewModel observa o repository, transforma domínio em estado de UI e a tela Compose apenas renderiza.\nclass PerfilViewModel( private val repository: PerfilRepository, ) : ViewModel() { private val usuarioId = MutableStateFlow\u0026lt;String?\u0026gt;(null) val uiState: StateFlow\u0026lt;PerfilUiState\u0026gt; = usuarioId .filterNotNull() .flatMapLatest { id -\u0026gt; repository.observarPerfil(id) } .map { perfil -\u0026gt; PerfilUiState.Carregado(perfil) } .catch { erro -\u0026gt; emit(PerfilUiState.Erro(erro.message.orEmpty())) } .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = PerfilUiState.Carregando, ) } Esse modelo conversa bem com Jetpack Compose, porque evita callback solto e concentra loading, erro e dados em um único estado observável.\nCache normalizado não é cache mágico Um dos recursos mais poderosos do Apollo é o cache normalizado. Em vez de guardar apenas a resposta bruta de cada query, o client pode armazenar entidades por identificador. Se duas queries retornam o mesmo Usuario, atualizar uma pode refletir na outra.\nIsso é útil, mas exige disciplina. O schema precisa expor IDs estáveis. O time precisa decidir quando ler da rede, quando aceitar cache e quando invalidar dados. Sem essa política, a tela pode exibir informação antiga em momentos sensíveis.\nUma estratégia prática:\nuse cache para dados de leitura frequente e baixa criticidade, como perfil resumido, categorias e preferências visuais; force rede para ações críticas, como pagamento, confirmação de pedido ou mudança de permissão; registre claramente o estado “atualizando” quando a UI mostra cache enquanto busca dados novos; combine cache GraphQL com Room apenas quando houver uma razão clara para consulta local, histórico ou modo offline robusto. Se o app precisa funcionar sem internet de verdade, veja GraphQL como camada de sincronização, não como substituto automático para banco local. A arquitetura offline-first ainda costuma precisar de Room, fila de operações pendentes e WorkManager.\nTratamento de erros em GraphQL REST costuma sinalizar falhas principalmente por status HTTP. GraphQL pode retornar HTTP 200 com campo errors quando parte da operação falhou. Isso muda o desenho do tratamento de erro.\nNo Android, separe pelo menos quatro categorias:\nerro de rede, como timeout, DNS ou ausência de conexão; erro HTTP, como 401, 403 ou 500; erro GraphQL de negócio, vindo no array errors; dado ausente ou incompatível com o estado esperado pela tela. Não transforme tudo em “algo deu errado”. Para o usuário, uma sessão expirada pede login; uma conexão instável pede tentar novamente; uma regra de negócio pode pedir ajuste de formulário; um bug de contrato deve ir para observabilidade.\nTambém vale mapear erros para tipos de domínio:\nsealed interface FalhaPerfil { data object SemInternet : FalhaPerfil data object NaoAutorizado : FalhaPerfil data class RegraNegocio(val mensagem: String) : FalhaPerfil data class Desconhecida(val causa: Throwable?) : FalhaPerfil } Esse tipo de modelagem deixa testes mais simples e evita try/catch repetido em cada ViewModel.\nTestando queries e repositories Testar GraphQL no Android não precisa depender sempre de servidor real. Para lógica de mapeamento, use respostas falsas ou mocks do client. Para integração, mantenha testes que validem operações críticas contra um ambiente controlado ou contrato gerado.\nO que vale testar:\nquery bem-sucedida mapeia corretamente para modelo de domínio; resposta com errors vira falha de negócio; ausência de dados obrigatórios não quebra a tela silenciosamente; ViewModel emite loading, sucesso e erro na ordem esperada; cache não mostra dados de um usuário para outro após logout. Se o app usa Flow, ferramentas como Turbine ajudam a validar emissões. O guia de testes em Kotlin aprofunda esse ponto com kotlinx-coroutines-test, MockK e estratégias para código assíncrono.\nGraphQL em entrevistas e vagas Android Em entrevistas, saber “chamar uma query” é só o começo. O que diferencia uma pessoa Android mais forte é explicar trade-offs: por que GraphQL reduz overfetching, como lidar com erros parciais, quando cache normalizado ajuda, quando REST é suficiente e como evitar acoplamento excessivo entre schema e UI.\nUm bom projeto de portfólio pode ter uma tela de catálogo, uma tela de perfil e uma tela de detalhes consumindo GraphQL, com repository, estados de UI, testes e tratamento explícito de erro. Se você quer reforçar o lado de carreira, conecte esse projeto ao seu portfólio de desenvolvedor Kotlin e ao roadmap Android.\nPara quem também trabalha no backend, vale comparar com APIs REST em outras linguagens. O ecossistema de Go para APIs de alta performance e o de Python para prototipagem de APIs ajudam a entender por que GraphQL costuma entrar como camada de composição, não como substituto universal para todo endpoint.\nChecklist prático para produção Antes de colocar GraphQL em produção no Android, revise:\nschema versionado e revisado junto com backend; queries pequenas, orientadas a tela, sem campos inúteis; autenticação centralizada no ApolloClient; mapeamento de DTO gerado para modelos de domínio; tratamento separado para rede, HTTP, GraphQL e dados ausentes; política clara de cache e logout; testes de repository e ViewModel; logs sem dados sensíveis; métricas de latência, falhas e tamanho de resposta. GraphQL com Kotlin funciona muito bem quando o time trata contrato, cache, erros e arquitetura como partes do mesmo sistema. Apollo Kotlin entrega a base técnica; a qualidade vem de usar essa base sem jogar regra de negócio na tela, sem esconder falhas parciais e sem transformar cache em fonte de inconsistência. Em 2026, esse é um conhecimento valioso para Android, backend-for-frontend e equipes que precisam evoluir produto rápido sem perder segurança no app mobile.\n","permalink":"https://kotlin.dev.br/blog/graphql-android-kotlin-apollo-2026/","summary":"\u003cp\u003eGraphQL aparece cada vez mais em vagas Android porque resolve um problema real de produto: telas mobile raramente precisam exatamente do mesmo payload que o backend REST já expõe. Uma home pode precisar de nome do usuário, saldo resumido, banners, atalhos e notificações; uma tela de detalhe pode misturar informações de catálogo, preço, disponibilidade e recomendações. Quando cada tela depende de várias chamadas REST, o app fica mais sensível a latência, versionamento e campos desnecessários.\u003c/p\u003e","title":"GraphQL no Android com Kotlin: Apollo em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA GFT busca Desenvolvedor Java / Kotlin Sênior para atuação presencial em Barueri, São Paulo.\nResponsabilidadesDesenvolver e manter aplicações backend com Java, Kotlin e Spring.Construir e integrar APIs REST e arquiteturas baseadas em microserviços.Trabalhar com bancos de dados SQL e NoSQL.Apoiar práticas de CI/CD, versionamento com Git e automação de entregas.Atuar com ambientes conteinerizados usando Docker e Kubernetes.RequisitosExperiência sênior em desenvolvimento backend com Java e Kotlin.Conhecimento em Spring, REST e microserviços.Experiência com Docker, Kubernetes, Git e pipelines de CI/CD.Conhecimento em Azure DevOps.Experiência com bancos SQL e NoSQL.Disponibilidade para trabalho presencial em Barueri. ","permalink":"https://kotlin.dev.br/vagas/8cchdlnip7d4h3bc-gft-desenvolvedor-java-kotlin-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA GFT busca Desenvolvedor Java / Kotlin Sênior para atuação presencial em Barueri, São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações backend com Java, Kotlin e Spring.\u003c/li\u003e\u003cli\u003eConstruir e integrar APIs REST e arquiteturas baseadas em microserviços.\u003c/li\u003e\u003cli\u003eTrabalhar com bancos de dados SQL e NoSQL.\u003c/li\u003e\u003cli\u003eApoiar práticas de CI/CD, versionamento com Git e automação de entregas.\u003c/li\u003e\u003cli\u003eAtuar com ambientes conteinerizados usando Docker e Kubernetes.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento backend com Java e Kotlin.\u003c/li\u003e\u003cli\u003eConhecimento em Spring, REST e microserviços.\u003c/li\u003e\u003cli\u003eExperiência com Docker, Kubernetes, Git e pipelines de CI/CD.\u003c/li\u003e\u003cli\u003eConhecimento em Azure DevOps.\u003c/li\u003e\u003cli\u003eExperiência com bancos SQL e NoSQL.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho presencial em Barueri.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Java / Kotlin Sênior"},{"content":"Sobre a vagaA Mindera busca uma pessoa Desenvolvedora Mobile Sênior com foco em Android. A vaga é remota e vinculada a Blumenau, Santa Catarina, Brasil.\nStack e conhecimentosKotlin para desenvolvimento Android.Jetpack Compose para construção de interfaces.Kotlin Multiplatform para compartilhamento de código entre plataformas.Arquitetura MVVM.Programação assíncrona com Coroutines e RxJava.Experiência com testes unitários e testes de UI.SenioridadeNível sênior.\n","permalink":"https://kotlin.dev.br/vagas/5dtvcwfosbgx10gk-mindera-desenvolvedor-a-mobile-senior-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Mindera busca uma pessoa Desenvolvedora Mobile Sênior com foco em Android. A vaga é remota e vinculada a Blumenau, Santa Catarina, Brasil.\u003c/p\u003e\u003ch3\u003eStack e conhecimentos\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eKotlin\u003c/strong\u003e para desenvolvimento Android.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eJetpack Compose\u003c/strong\u003e para construção de interfaces.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eKotlin Multiplatform\u003c/strong\u003e para compartilhamento de código entre plataformas.\u003c/li\u003e\u003cli\u003eArquitetura \u003cstrong\u003eMVVM\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eProgramação assíncrona com \u003cstrong\u003eCoroutines\u003c/strong\u003e e \u003cstrong\u003eRxJava\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003etestes unitários\u003c/strong\u003e e \u003cstrong\u003etestes de UI\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade\u003c/h3\u003e\u003cp\u003eNível sênior.\u003c/p\u003e","title":"Desenvolvedor(a) Mobile Sênior (Android)"},{"content":"Sobre a vagaA Wellhub busca uma pessoa Engenheira de Software Backend Sênior para atuar na área de Conquistas e Gamificação. A vaga é remota, com localização informada como Brasil ou São Paulo.\nStack técnicaLinguagens: Kotlin, Go, Scala e Java.Bancos de dados: PostgreSQL, MySQL, DynamoDB e Redis.Mensageria e eventos: Kafka, RabbitMQ e SNS.Cloud: AWS.Práticas de engenharia: TDD.RequisitosExperiência sênior em desenvolvimento Backend.Vivência com sistemas distribuídos, bancos relacionais e NoSQL.Experiência com mensageria, arquitetura orientada a eventos e serviços em cloud.Capacidade de atuar em produtos ligados a conquistas, engajamento e gamificação. ","permalink":"https://kotlin.dev.br/vagas/vz4jfkqe35tg00mt-wellhub-engenheiro-a-de-software-backend-senior-conquistas-e-ga/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Wellhub busca uma pessoa \u003cstrong\u003eEngenheira de Software Backend Sênior\u003c/strong\u003e para atuar na área de Conquistas e Gamificação. A vaga é remota, com localização informada como Brasil ou São Paulo.\u003c/p\u003e\u003ch3\u003eStack técnica\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLinguagens: Kotlin, Go, Scala e Java.\u003c/li\u003e\u003cli\u003eBancos de dados: PostgreSQL, MySQL, DynamoDB e Redis.\u003c/li\u003e\u003cli\u003eMensageria e eventos: Kafka, RabbitMQ e SNS.\u003c/li\u003e\u003cli\u003eCloud: AWS.\u003c/li\u003e\u003cli\u003ePráticas de engenharia: TDD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Backend.\u003c/li\u003e\u003cli\u003eVivência com sistemas distribuídos, bancos relacionais e NoSQL.\u003c/li\u003e\u003cli\u003eExperiência com mensageria, arquitetura orientada a eventos e serviços em cloud.\u003c/li\u003e\u003cli\u003eCapacidade de atuar em produtos ligados a conquistas, engajamento e gamificação.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Backend Sênior | Conquistas e Gamificação"},{"content":"Sobre a vagaVaga remota para Pessoa Desenvolvedora Backend Kotlin Sênior na Zup Innovation, com atuação em sistemas backend, APIs e microsserviços.\nRequisitosExperiência sênior com desenvolvimento backend em Kotlin.Conhecimento em AWS e API Gateway.Experiência com construção e integração de REST APIs.Vivência com arquitetura de microsserviços.Experiência com sistemas orientados a eventos.Uso de Git no fluxo de desenvolvimento.Local de trabalhoAtuação remota, com localização informada em São Paulo, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/4bptcrjpdiiej4qg-zup-innovation-pessoa-desenvolvedora-backend-kotlin-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga remota para Pessoa Desenvolvedora Backend Kotlin Sênior na Zup Innovation, com atuação em sistemas backend, APIs e microsserviços.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com desenvolvimento backend em \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eAWS\u003c/strong\u003e e \u003cstrong\u003eAPI Gateway\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com construção e integração de \u003cstrong\u003eREST APIs\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com arquitetura de \u003cstrong\u003emicrosserviços\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com sistemas orientados a eventos.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eGit\u003c/strong\u003e no fluxo de desenvolvimento.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eAtuação remota, com localização informada em São Paulo, São Paulo, Brasil.\u003c/p\u003e","title":"Pessoa Desenvolvedora Backend Kotlin Sênior"},{"content":"Sobre a vagaVaga presencial em São Paulo para Pessoa Desenvolvedora Backend Pleno Kotlin/Java na área de Core Business Products Engineering do C6 Bank.\nResponsabilidadesDesenvolver e manter serviços backend para produtos core do negócio.Atuar com arquitetura de microsserviços, integrações e mensageria.Contribuir com automação, observabilidade, testes e práticas de infraestrutura como código.Trabalhar com requisitos de segurança e protocolos aplicáveis a sistemas financeiros.RequisitosExperiência com Kotlin e Java no desenvolvimento backend.Conhecimento de Spring Boot e arquitetura de microsserviços.Experiência com bancos de dados como PostgreSQL, MongoDB ou Cassandra.Vivência com mensageria usando Kafka, SQS ou SNS.Conhecimento de AWS, Terraform, observabilidade, automação e testes. ","permalink":"https://kotlin.dev.br/vagas/btf63oze3qer7vie-c6-bank-pessoa-desenvolvedora-backend-pleno-kotlin-java/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga presencial em São Paulo para Pessoa Desenvolvedora Backend Pleno Kotlin/Java na área de Core Business Products Engineering do C6 Bank.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend para produtos core do negócio.\u003c/li\u003e\u003cli\u003eAtuar com arquitetura de microsserviços, integrações e mensageria.\u003c/li\u003e\u003cli\u003eContribuir com automação, observabilidade, testes e práticas de infraestrutura como código.\u003c/li\u003e\u003cli\u003eTrabalhar com requisitos de segurança e protocolos aplicáveis a sistemas financeiros.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin e Java no desenvolvimento backend.\u003c/li\u003e\u003cli\u003eConhecimento de Spring Boot e arquitetura de microsserviços.\u003c/li\u003e\u003cli\u003eExperiência com bancos de dados como PostgreSQL, MongoDB ou Cassandra.\u003c/li\u003e\u003cli\u003eVivência com mensageria usando Kafka, SQS ou SNS.\u003c/li\u003e\u003cli\u003eConhecimento de AWS, Terraform, observabilidade, automação e testes.\u003c/li\u003e\u003c/ul\u003e","title":"Pessoa Desenvolvedora Backend Pleno Kotlin/Java"},{"content":"RAG, ou Retrieval-Augmented Generation, virou uma das formas mais pragmáticas de levar IA generativa para aplicações reais sem depender apenas da memória estatística de um modelo. Em vez de pedir para o LLM “saber tudo”, a aplicação busca documentos relevantes em uma base controlada, monta um contexto e só então chama o modelo para responder. Para times que já usam Kotlin no backend, o Spring AI torna esse fluxo mais familiar, porque encaixa embeddings, vector stores, prompts e clientes de modelo dentro do ecossistema Spring Boot.\nEsse assunto interessa especialmente a quem trabalha com produto interno, suporte técnico, base de conhecimento, documentação, atendimento, busca semântica ou automação corporativa. Kotlin entra como uma ótima escolha quando o sistema de IA precisa ficar perto de regras de domínio, APIs existentes, autenticação, filas, bancos relacionais e observabilidade. Se você ainda está escolhendo a base do backend, leia também nosso guia de Kotlin para backend, o artigo sobre Kotlin com Spring Boot e a introdução a Kotlin e IA/Machine Learning.\nO que RAG resolve na prática Um chatbot simples, sem recuperação de contexto, depende do conhecimento geral do modelo e do texto enviado diretamente no prompt. Isso funciona para perguntas genéricas, mas falha quando a resposta precisa refletir políticas internas, documentação privada, contratos, changelogs, manuais, catálogo de produtos ou estado atualizado do negócio.\nRAG adiciona uma etapa intermediária. Quando o usuário pergunta algo, a aplicação transforma a pergunta em embedding, busca trechos semanticamente próximos em um vector store, seleciona os melhores resultados e injeta esses trechos no prompt. O modelo continua gerando linguagem natural, mas agora responde com base em material que a aplicação escolheu.\nEsse padrão reduz alucinações, facilita atualização de conhecimento sem retreinar modelo e melhora rastreabilidade. Você consegue guardar quais documentos foram usados, mostrar fontes na resposta e auditar por que o sistema chegou a determinada conclusão. Não é mágica: se os documentos são ruins, desatualizados ou mal segmentados, a resposta também sofre. Mas o controle operacional é muito maior do que em um prompt solto.\nArquitetura básica com Kotlin e Spring AI Uma aplicação RAG em Kotlin costuma ter cinco peças:\nPipeline de ingestão: lê documentos, quebra em pedaços menores e gera embeddings. Vector store: armazena embeddings e metadados para busca semântica. Serviço de pergunta: recebe a consulta do usuário e busca trechos relevantes. Prompt template: combina pergunta, contexto recuperado e instruções de resposta. Camada de resposta: devolve texto, fontes, confiança operacional e logs. Em Spring AI, essas responsabilidades aparecem como beans e serviços comuns de Spring Boot. O ponto importante é não colocar tudo dentro do controller. O controller deve validar entrada e chamar um serviço; o serviço coordena busca, prompt e modelo; a infraestrutura fica isolada atrás de interfaces. Essa separação conversa bem com Clean Architecture em Kotlin e facilita testes.\nUm serviço simplificado pode ter esta cara:\n@Service class PerguntasRagService( private val chatClient: ChatClient, private val vectorStore: VectorStore, ) { fun responder(pergunta: String): RespostaRag { val documentos = vectorStore.similaritySearch( SearchRequest.query(pergunta).withTopK(5) ) val contexto = documentos.joinToString(\u0026#34;\\n\\n\u0026#34;) { documento -\u0026gt; \u0026#34;Fonte: ${documento.metadata[\u0026#34;fonte\u0026#34;]}\\n${documento.content}\u0026#34; } val resposta = chatClient.prompt() .system(\u0026#34;Responda em português brasileiro, usando apenas o contexto fornecido.\u0026#34;) .user(\u0026#34;\u0026#34;\u0026#34; Contexto: $contexto Pergunta: $pergunta \u0026#34;\u0026#34;\u0026#34;.trimIndent()) .call() .content() return RespostaRag( texto = resposta.orEmpty(), fontes = documentos.mapNotNull { it.metadata[\u0026#34;fonte\u0026#34;]?.toString() } ) } } O exemplo é curto de propósito. Em produção, você vai querer tratamento de erro, timeout, limites de tamanho, logging estruturado, cache quando fizer sentido e validação de permissões por documento. Ainda assim, a ideia central já aparece: o modelo não responde sozinho; ele responde com base no que a busca recuperou.\nIngestão: onde muitos projetos erram A parte mais subestimada de RAG não é chamar o LLM. É preparar os documentos. Um pipeline ruim cria chunks grandes demais, pequenos demais, sem metadados, sem versão e sem relação clara com a fonte original. Depois, quando a resposta sai incompleta, o time tenta “melhorar o prompt”, mas o problema estava na recuperação.\nPara Kotlin com Spring AI, pense na ingestão como um processo explícito:\n@Component class IngestaoDocumentos( private val vectorStore: VectorStore, private val embeddingModel: EmbeddingModel, ) { fun indexar(documentos: List\u0026lt;DocumentoFonte\u0026gt;) { val chunks = documentos.flatMap { documento -\u0026gt; documento.texto.chunked(1_500).mapIndexed { indice, trecho -\u0026gt; Document( trecho, mapOf( \u0026#34;fonte\u0026#34; to documento.url, \u0026#34;titulo\u0026#34; to documento.titulo, \u0026#34;chunk\u0026#34; to indice, \u0026#34;versao\u0026#34; to documento.versao, ) ) } } vectorStore.add(chunks) } } Na prática, chunked(1_500) é simplista. Um pipeline melhor respeita parágrafos, títulos, seções, tabelas e blocos de código. Documentação técnica, por exemplo, não deveria cortar uma função no meio. Políticas internas não deveriam separar exceção e regra principal em chunks desconectados. Se o conteúdo tem hierarquia, preserve essa hierarquia nos metadados.\nTambém vale manter versionamento. Quando um documento muda, você precisa saber se o vector store contém a versão nova ou uma versão antiga. Para bases pequenas, reindexar tudo pode ser aceitável. Para bases maiores, um processo incremental por hash de conteúdo evita custo desnecessário.\nPrompt: seja explícito sobre limites Um bom prompt de RAG não precisa ser poético. Ele precisa ser operacional. Diga ao modelo para responder em português brasileiro, usar apenas o contexto, admitir quando não houver informação suficiente e listar fontes quando possível. Isso reduz respostas inventadas e cria uma experiência mais confiável para o usuário.\nExemplo de instrução de sistema:\nVocê é um assistente técnico. Responda em português brasileiro. Use apenas o contexto fornecido pela aplicação. Se o contexto não contiver a resposta, diga que não há informação suficiente. Não invente números, políticas, links ou nomes de responsáveis. Quando usar uma fonte, mencione o título ou URL fornecido nos metadados. Essa instrução não elimina alucinação por completo, mas estabelece um contrato. O contrato também deve ser reforçado na aplicação: limite temperatura quando o caso exigir precisão, recuse perguntas fora de escopo e registre quais fontes entraram no prompt. Se o sistema responde sobre documentos internos, autorização é parte do RAG. Não basta recuperar o documento semanticamente correto; o usuário precisa ter permissão para vê-lo.\nTestes para RAG em Kotlin Testar RAG exige uma mentalidade diferente de testes unitários tradicionais. Você não deve comparar a resposta inteira caractere por caractere, porque modelos podem variar. Em vez disso, teste contratos observáveis.\nAlguns testes úteis:\nquando a pergunta menciona um tema existente, a busca recupera documentos esperados; quando não há contexto suficiente, o serviço não inventa resposta; fontes usadas na resposta aparecem no objeto retornado; documentos sem permissão não entram no contexto; prompts respeitam limite máximo de tokens ou caracteres; erros do provedor de IA viram respostas controladas, não stack traces para o usuário. Você pode combinar testes unitários com mocks para o VectorStore e o ChatClient, além de testes de integração com uma base pequena e determinística. O artigo sobre JUnit 5 e MockK em Kotlin complementa bem essa etapa, e o guia de CI/CD para Kotlin mostra como levar essas verificações para o pipeline.\nObservabilidade e custo RAG coloca uma dependência cara e variável no caminho da requisição. Cada pergunta pode consumir embeddings, busca vetorial, tokens de prompt, tokens de resposta e chamadas externas. Por isso, observe desde o início: latência da busca, tamanho do contexto, documentos recuperados, provedor chamado, custo estimado, taxa de erro e perguntas sem resposta.\nSe o time já usa OpenTelemetry, trace a operação inteira: controller, busca no vector store, chamada ao modelo e pós-processamento. Em aplicações com agentes ou fluxos mais complexos, vale ler também o artigo sobre Tracy para observabilidade de IA em Kotlin. A regra é simples: se você não consegue explicar por que a resposta ficou lenta, cara ou errada, ainda não tem uma operação madura.\nQuando Spring AI faz sentido Spring AI é uma boa escolha quando sua aplicação já está no mundo Spring Boot ou quando o time quer padronizar integração com modelos, embeddings e vector stores sem criar uma camada própria do zero. Ele combina especialmente com backend Kotlin, APIs REST, autenticação via Spring Security, jobs de ingestão, mensageria e bancos já existentes.\nSe o projeto é um protótipo rápido de ciência de dados, Python ainda pode ser mais direto. O ecossistema Python domina notebooks, avaliação de modelos e experimentação com IA. Mas quando a IA precisa virar produto backend integrado a sistemas JVM, Kotlin ganha força. Para serviços pequenos e binários simples, Go também é uma alternativa forte; para componentes de performance crítica, Rust pode complementar a arquitetura.\nChecklist para colocar em produção Antes de publicar um recurso RAG para usuários reais, revise este checklist:\ndocumentos têm fonte, versão, data e permissões; chunks preservam sentido e não cortam trechos críticos; busca vetorial foi avaliada com perguntas reais; prompt manda admitir falta de contexto; resposta retorna fontes quando possível; logs não vazam dados sensíveis; custos e latência estão monitorados; testes cobrem recuperação, autorização e fallback; existe processo para reindexar conteúdo atualizado. RAG com Kotlin e Spring AI não é apenas “colocar IA no backend”. É um projeto de engenharia de informação. O valor aparece quando documentos bons, busca semântica, prompts objetivos, testes e observabilidade trabalham juntos. Para times Kotlin, essa combinação permite entregar IA generativa com mais controle, mantendo a aplicação próxima do ecossistema JVM que já sustenta APIs, jobs, regras de negócio e integrações críticas.\n","permalink":"https://kotlin.dev.br/blog/kotlin-spring-ai-rag-2026/","summary":"\u003cp\u003eRAG, ou \u003cstrong\u003eRetrieval-Augmented Generation\u003c/strong\u003e, virou uma das formas mais pragmáticas de levar IA generativa para aplicações reais sem depender apenas da memória estatística de um modelo. Em vez de pedir para o LLM “saber tudo”, a aplicação busca documentos relevantes em uma base controlada, monta um contexto e só então chama o modelo para responder. Para times que já usam Kotlin no backend, o Spring AI torna esse fluxo mais familiar, porque encaixa embeddings, vector stores, prompts e clientes de modelo dentro do ecossistema Spring Boot.\u003c/p\u003e","title":"RAG com Kotlin e Spring AI em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA Hotmart busca uma pessoa Engenheira de Software Sênior Backend para atuação presencial em Minas Gerais.\nTecnologiasKotlinJavaPythonAWS, GCP e AzureCI/CDAPIs e LLM APIsPerfilVaga de nível sênior para desenvolvimento Backend, com foco em construção e evolução de APIs, integração com serviços em nuvem e práticas de entrega contínua.\n","permalink":"https://kotlin.dev.br/vagas/cmanyxbpngxyoztr-hotmart-engenheiro-a-de-software-senior-backend/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Hotmart busca uma pessoa Engenheira de Software Sênior Backend para atuação presencial em Minas Gerais.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003ePython\u003c/li\u003e\u003cli\u003eAWS, GCP e Azure\u003c/li\u003e\u003cli\u003eCI/CD\u003c/li\u003e\u003cli\u003eAPIs e LLM APIs\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cp\u003eVaga de nível sênior para desenvolvimento Backend, com foco em construção e evolução de APIs, integração com serviços em nuvem e práticas de entrega contínua.\u003c/p\u003e","title":"Engenheiro(a) de Software Sênior Backend"},{"content":"Usar Kotlin com PostgreSQL é uma das combinações mais fortes para quem quer trabalhar com backend JVM em 2026. Kotlin entrega uma linguagem concisa, segura contra nulos e muito produtiva; PostgreSQL entrega um banco relacional maduro, confiável, com ótimo suporte a índices, JSONB, transações e extensões. Juntos, eles aparecem com frequência em APIs internas, fintechs, e-commerce, plataformas SaaS e vagas de backend Kotlin no Brasil.\nEste tutorial mostra um caminho prático para sair do \u0026ldquo;consigo conectar no banco\u0026rdquo; e chegar em uma estrutura que dá para evoluir: schema organizado, conexão com pool, acesso via Exposed, migrations, transações, testes e decisões de produção. Se você está estudando backend, leia também o roadmap para desenvolvedor backend Kotlin, o guia de Ktor e o tutorial de Spring Boot com Kotlin.\nQuando escolher PostgreSQL em um backend Kotlin? PostgreSQL é uma boa escolha quando seus dados têm relacionamento claro, precisam de consistência e serão consultados por filtros variados. Usuários, pedidos, pagamentos, permissões, auditoria, assinaturas e catálogos são exemplos clássicos. Mesmo quando o produto cresce, o PostgreSQL continua competitivo porque oferece transações ACID, constraints, índices parciais, views, funções, JSONB e extensões como pg_trgm para busca textual.\nEm Kotlin, ele combina bem com três estilos comuns:\nKtor + Exposed para APIs leves e idiomáticas; Spring Boot + Spring Data JPA para sistemas corporativos com ecossistema amplo; jOOQ quando o time quer SQL explícito e geração de código type-safe. Não existe uma única resposta certa. Para aprender e criar APIs enxutas, Ktor com Exposed é direto. Para times que já usam Spring, Spring Boot reduz atrito. Para domínios com SQL complexo, jOOQ pode ser mais transparente que um ORM tradicional.\nDependências básicas com Gradle Kotlin DSL O exemplo abaixo usa Exposed com JDBC e HikariCP. É um ponto de partida simples para uma API Ktor ou um serviço Kotlin puro:\nplugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.3.20\u0026#34; application } repositories { mavenCentral() } dependencies { implementation(\u0026#34;org.jetbrains.exposed:exposed-core:1.0.0\u0026#34;) implementation(\u0026#34;org.jetbrains.exposed:exposed-dao:1.0.0\u0026#34;) implementation(\u0026#34;org.jetbrains.exposed:exposed-jdbc:1.0.0\u0026#34;) implementation(\u0026#34;org.jetbrains.exposed:exposed-java-time:1.0.0\u0026#34;) implementation(\u0026#34;org.postgresql:postgresql:42.7.4\u0026#34;) implementation(\u0026#34;com.zaxxer:HikariCP:6.2.1\u0026#34;) testImplementation(kotlin(\u0026#34;test\u0026#34;)) } Se você está usando Ktor, combine isso com ContentNegotiation, kotlinx.serialization e rotas HTTP. Se está usando Spring Boot, talvez prefira spring-boot-starter-data-jpa ou spring-jdbc, mas os conceitos de schema, migrations, transações e testes continuam os mesmos.\nConfigurando o pool de conexões Nunca abra uma nova conexão manualmente a cada request. Em produção, use um pool. O HikariCP é o padrão de fato no ecossistema JVM e funciona bem com Kotlin:\nimport com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import org.jetbrains.exposed.sql.Database fun conectarPostgres() { val config = HikariConfig().apply { jdbcUrl = System.getenv(\u0026#34;DATABASE_URL\u0026#34;) ?: \u0026#34;jdbc:postgresql://localhost:5432/app\u0026#34; username = System.getenv(\u0026#34;DATABASE_USER\u0026#34;) ?: \u0026#34;app\u0026#34; password = System.getenv(\u0026#34;DATABASE_PASSWORD\u0026#34;) ?: \u0026#34;app\u0026#34; maximumPoolSize = 10 minimumIdle = 2 isAutoCommit = false transactionIsolation = \u0026#34;TRANSACTION_REPEATABLE_READ\u0026#34; validate() } Database.connect(HikariDataSource(config)) } O detalhe importante é tratar configuração como ambiente, não como código. DATABASE_URL, usuário e senha devem vir do ambiente de deploy ou do gerenciador de secrets. Em desenvolvimento local, um docker-compose.yml com PostgreSQL resolve. Em produção, prefira um serviço gerenciado quando o time não quer operar backup, replicação e atualizações manualmente.\nModelando tabelas com Exposed Exposed representa tabelas como objetos Kotlin. Isso dá autocompletar, tipos explícitos e menos strings soltas espalhadas pelo código:\nimport org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.javatime.datetime object Clientes : Table(\u0026#34;clientes\u0026#34;) { val id = uuid(\u0026#34;id\u0026#34;) val nome = varchar(\u0026#34;nome\u0026#34;, 160) val email = varchar(\u0026#34;email\u0026#34;, 255).uniqueIndex() val ativo = bool(\u0026#34;ativo\u0026#34;).default(true) val criadoEm = datetime(\u0026#34;criado_em\u0026#34;) override val primaryKey = PrimaryKey(id) } object Pedidos : Table(\u0026#34;pedidos\u0026#34;) { val id = uuid(\u0026#34;id\u0026#34;) val clienteId = uuid(\u0026#34;cliente_id\u0026#34;).references(Clientes.id) val status = varchar(\u0026#34;status\u0026#34;, 40) val totalCentavos = long(\u0026#34;total_centavos\u0026#34;) val criadoEm = datetime(\u0026#34;criado_em\u0026#34;) override val primaryKey = PrimaryKey(id) } Mesmo usando DSL, pense primeiro no banco. Defina chaves primárias, chaves estrangeiras, constraints, índices e nomes estáveis. Kotlin ajuda na camada de aplicação, mas a integridade dos dados deve continuar protegida no PostgreSQL. Um bug em uma rota não pode ser capaz de gravar pedido sem cliente ou e-mail duplicado se o banco estiver modelado corretamente.\nCRUD simples com transações Toda operação que lê e escreve dados relacionados deve estar dentro de uma transação. Com Exposed, o bloco transaction deixa isso explícito:\nimport org.jetbrains.exposed.sql.insert import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.transactions.transaction import java.time.LocalDateTime import java.util.UUID data class NovoCliente(val nome: String, val email: String) fun criarCliente(input: NovoCliente): UUID = transaction { val id = UUID.randomUUID() Clientes.insert { it[Clientes.id] = id it[nome] = input.nome.trim() it[email] = input.email.lowercase().trim() it[ativo] = true it[criadoEm] = LocalDateTime.now() } id } fun listarClientesAtivos(): List\u0026lt;NovoCliente\u0026gt; = transaction { Clientes .selectAll() .where { Clientes.ativo eq true } .map { row -\u0026gt; NovoCliente( nome = row[Clientes.nome], email = row[Clientes.email] ) } } Para APIs Ktor, chame funções de repositório a partir das rotas e mantenha validação de entrada antes da transação. Para Spring Boot, encapsule regras em services e use @Transactional quando fizer sentido. Em qualquer stack, evite misturar regra de negócio complexa diretamente no handler HTTP.\nMigrations: não crie schema no startup É tentador usar SchemaUtils.create() em todo boot. Isso serve para protótipos, mas não para produção. Em um sistema real, mudanças no banco precisam ser versionadas. Use Flyway ou Liquibase para manter um histórico claro:\n-- V1__criar_clientes_e_pedidos.sql CREATE TABLE clientes ( id UUID PRIMARY KEY, nome VARCHAR(160) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE, ativo BOOLEAN NOT NULL DEFAULT true, criado_em TIMESTAMP NOT NULL ); CREATE TABLE pedidos ( id UUID PRIMARY KEY, cliente_id UUID NOT NULL REFERENCES clientes(id), status VARCHAR(40) NOT NULL, total_centavos BIGINT NOT NULL, criado_em TIMESTAMP NOT NULL ); CREATE INDEX idx_pedidos_cliente_id ON pedidos(cliente_id); CREATE INDEX idx_pedidos_status ON pedidos(status); Migrations são especialmente importantes quando há mais de uma instância da aplicação rodando, quando o deploy é automatizado ou quando você precisa auditar por que uma coluna mudou. Elas também ajudam entrevistas e portfólio: demonstram que você entende ciclo de vida de banco, não apenas código Kotlin.\nÍndices e consultas que importam Um erro comum é criar índice em toda coluna. Índice acelera leitura, mas custa escrita e espaço. Comece pelos filtros reais da aplicação:\nemail único para login ou identificação; chaves estrangeiras usadas em joins; status quando filas operacionais filtram pedidos pendentes; criado_em quando telas listam eventos recentes; índices compostos quando a consulta filtra por mais de uma coluna. Use EXPLAIN ANALYZE quando uma query ficar lenta. Em Kotlin, a abstração não elimina a necessidade de entender SQL. Se uma tela lista os últimos pedidos de um cliente, um índice em (cliente_id, criado_em DESC) pode ser mais útil que dois índices separados.\nTestando com PostgreSQL real Para lógica de domínio pura, testes unitários bastam. Para repositórios, teste contra PostgreSQL real sempre que possível. SQLite em memória não se comporta igual: tipos, constraints, JSONB, locks e funções diferem. Com Testcontainers, você sobe um PostgreSQL descartável no teste e valida migrations, queries e transações.\nMesmo que você não use Testcontainers no começo, pelo menos rode uma suíte local contra Docker antes de publicar mudanças importantes. Bugs de banco costumam aparecer tarde: timezone errado, coluna nullable sem querer, índice ausente, transação longa demais, deadlock por ordem inconsistente de atualização.\nChecklist para produção Antes de colocar um backend Kotlin com PostgreSQL no ar, confira:\nmigrations versionadas e revisadas; pool de conexões com tamanho compatível com o banco; timeouts configurados para queries e requests; logs sem senha, token ou dados sensíveis; backup e restore testados; índices para consultas críticas; transações curtas; validação de entrada antes de gravar; métricas de latência do banco e erros SQL; secrets fora do repositório. Esse checklist parece operacional, mas impacta diretamente a carreira. Muitas vagas de backend Kotlin pedem Spring Boot, Ktor, PostgreSQL, mensageria, Docker e cloud no mesmo pacote. Saber conectar esses pontos torna seu perfil mais forte do que apenas decorar sintaxe da linguagem.\nPróximos passos Se você quer evoluir este tema, construa uma API pequena com cadastro de clientes, pedidos e autenticação. Comece com Ktor e APIs REST, adicione PostgreSQL com Exposed, documente o contrato com OpenAPI e Swagger e depois escreva testes de integração. Para comparar caminhos, leia também Exposed 1.0 com R2DBC e o guia de microsserviços com Kotlin.\nKotlin com PostgreSQL não é uma combinação exótica: é uma base sólida para backend profissional. O diferencial está em usar a linguagem para escrever código mais claro sem abrir mão dos fundamentos de banco relacional: schema bem desenhado, transações corretas, SQL entendido e deploy seguro.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-postgresql-backend/","summary":"\u003cp\u003eUsar \u003cstrong\u003eKotlin com PostgreSQL\u003c/strong\u003e é uma das combinações mais fortes para quem quer trabalhar com backend JVM em 2026. Kotlin entrega uma linguagem concisa, segura contra nulos e muito produtiva; PostgreSQL entrega um banco relacional maduro, confiável, com ótimo suporte a índices, JSONB, transações e extensões. Juntos, eles aparecem com frequência em APIs internas, fintechs, e-commerce, plataformas SaaS e vagas de backend Kotlin no Brasil.\u003c/p\u003e\n\u003cp\u003eEste tutorial mostra um caminho prático para sair do \u0026ldquo;consigo conectar no banco\u0026rdquo; e chegar em uma estrutura que dá para evoluir: schema organizado, conexão com pool, acesso via Exposed, migrations, transações, testes e decisões de produção. Se você está estudando backend, leia também o \u003ca href=\"/carreira/roadmap-dev-backend-kotlin/\"\u003eroadmap para desenvolvedor backend Kotlin\u003c/a\u003e, o \u003ca href=\"/guias/guia-kotlin-backend-ktor/\"\u003eguia de Ktor\u003c/a\u003e e o \u003ca href=\"/tutoriais/kotlin-spring-boot-tutorial/\"\u003etutorial de Spring Boot com Kotlin\u003c/a\u003e.\u003c/p\u003e","title":"Kotlin com PostgreSQL: Backend Prático em 2026 | Kotlin Brasil"},{"content":"Construir um app Android que funciona bem apenas com internet perfeita é fácil. O desafio real aparece no ônibus, no elevador, no supermercado, no interior do Brasil, em redes corporativas instáveis ou quando o usuário abre o app com dados móveis fracos. É nesse cenário que a arquitetura offline-first com Kotlin deixa de ser luxo técnico e vira requisito de produto. Como esse desenho aumenta o volume de dados no dispositivo, vale tratar segurança de dados locais no Android como parte da arquitetura desde o começo.\nOffline-first significa que a experiência principal do app parte do armazenamento local. A interface lê dados locais de forma reativa, grava alterações primeiro no dispositivo e sincroniza com o servidor quando houver rede confiável. Em vez de tratar cache como remendo, o app assume que conexão é uma dependência incerta. Essa mentalidade combina muito bem com Kotlin, coroutines, Flow, Room, SQLDelight para KMP, DataStore Preferences e WorkManager.\nPara quem busca vagas Android em 2026, dominar esse desenho também é um diferencial forte. Muitas empresas brasileiras têm apps usados em campo, logística, vendas, delivery, finanças, saúde, educação e operações internas. Nesses contextos, “mostrar erro de conexão” a cada instabilidade não é aceitável.\nO que offline-first realmente quer dizer? Um app offline-first não é apenas um app que “salva alguma coisa em cache”. Ele precisa ter uma regra clara para três perguntas:\nde onde a tela lê os dados; onde uma mudança do usuário é registrada primeiro; como conflitos e falhas de sincronização são tratados. A resposta mais robusta costuma ser: a tela lê do banco local, a mudança é gravada localmente em uma fila de operações pendentes e a sincronização roda em background. O servidor continua sendo a fonte de verdade global, mas o dispositivo tem autonomia suficiente para manter a experiência utilizável.\nEssa diferença é importante. Um cache simples pode guardar a última resposta HTTP e expirar depois de alguns minutos. Offline-first vai além: o usuário consegue criar, editar, marcar, favoritar ou concluir ações mesmo sem rede, e o app sabe reconciliar essas ações depois.\nArquitetura recomendada para Android com Kotlin Uma arquitetura prática pode seguir quatro camadas:\nUI com Compose ou Views observando StateFlow; ViewModel convertendo fluxos do domínio em estado de tela; Repository decidindo entre banco local, rede e fila de sincronização; Data sources para Room, DataStore, API HTTP e WorkManager. Se você já estudou MVVM com Kotlin ou Clean Architecture em Kotlin, a ideia é familiar. A diferença é que o repository não deve ser apenas um pass-through para Retrofit. Ele vira o ponto que protege o restante do app contra instabilidade de rede.\nUm fluxo comum fica assim:\nclass TarefasRepository( private val dao: TarefaDao, private val api: TarefasApi, private val syncQueue: SyncQueue, ) { fun observarTarefas(): Flow\u0026lt;List\u0026lt;Tarefa\u0026gt;\u0026gt; = dao.observarTodas() .map { entidades -\u0026gt; entidades.map { it.toDomain() } } suspend fun concluirTarefa(id: Long) { dao.marcarComoConcluida(id, sincronizada = false) syncQueue.enfileirar( OperacaoSync.ConcluirTarefa(id = id) ) } suspend fun sincronizarPendentes() { syncQueue.pendentes().forEach { operacao -\u0026gt; when (operacao) { is OperacaoSync.ConcluirTarefa -\u0026gt; { api.concluirTarefa(operacao.id) dao.marcarComoSincronizada(operacao.id) syncQueue.remover(operacao.idLocal) } } } } } O ponto central é que a tela não espera a API responder para refletir a ação do usuário. Ela observa o Room; o Room muda imediatamente; a sincronização vem depois.\nRoom como fonte local reativa Room continua sendo uma escolha muito natural para Android offline-first porque integra bem com SQLite, Flow, migrations testadas e testes. Uma entidade offline-first normalmente precisa de metadados extras além dos campos de negócio.\n@Entity(tableName = \u0026#34;tarefas\u0026#34;) data class TarefaEntity( @PrimaryKey val id: Long, val titulo: String, val concluida: Boolean, val atualizadaEm: Instant, val sincronizada: Boolean, val removidaLocalmente: Boolean = false, ) @Dao interface TarefaDao { @Query(\u0026#34;SELECT * FROM tarefas WHERE removidaLocalmente = 0 ORDER BY atualizadaEm DESC\u0026#34;) fun observarTodas(): Flow\u0026lt;List\u0026lt;TarefaEntity\u0026gt;\u0026gt; @Query(\u0026#34;UPDATE tarefas SET concluida = 1, sincronizada = :sincronizada WHERE id = :id\u0026#34;) suspend fun marcarComoConcluida(id: Long, sincronizada: Boolean) @Query(\u0026#34;UPDATE tarefas SET sincronizada = 1 WHERE id = :id\u0026#34;) suspend fun marcarComoSincronizada(id: Long) } Campos como sincronizada, atualizadaEm e removidaLocalmente parecem detalhes, mas evitam bugs difíceis. Sem eles, o app não sabe se uma linha veio do servidor, foi alterada localmente ou precisa ser removida depois que a API confirmar.\nEm projetos maiores, também vale separar entidades locais de DTOs da API. Não use a resposta HTTP como modelo de banco sem pensar. O servidor pode mudar nomes, omitir campos ou representar estados de uma forma ruim para consulta local.\nDataStore para preferências e estado pequeno Room deve guardar dados estruturados e consultáveis. DataStore Preferences entra melhor para preferências, flags e pequenos estados de sincronização: último sync bem-sucedido, usuário selecionado, filtros salvos, token de paginação ou configuração de tema.\nclass SyncPreferences( private val dataStore: DataStore\u0026lt;Preferences\u0026gt;, ) { private val ultimaSyncKey = stringPreferencesKey(\u0026#34;ultima_sync\u0026#34;) val ultimaSync: Flow\u0026lt;Instant?\u0026gt; = dataStore.data.map { prefs -\u0026gt; prefs[ultimaSyncKey]?.let(Instant::parse) } suspend fun registrarSyncAgora(clock: Clock) { dataStore.edit { prefs -\u0026gt; prefs[ultimaSyncKey] = clock.now().toString() } } } Evite colocar listas grandes em DataStore. Quando você perceber que precisa filtrar, ordenar, paginar ou relacionar dados, o lugar correto provavelmente é Room.\nWorkManager para sincronização confiável WorkManager é a peça certa para sincronização que precisa sobreviver a fechamento do app, reinício do aparelho e variações de rede. Ele não substitui coroutines no repository, mas resolve uma necessidade específica: executar trabalho adiado com restrições. Se você quer aprofundar agendamento, retry, constraints e testes, veja o guia dedicado de WorkManager com Kotlin no Android.\nclass SincronizarTarefasWorker( context: Context, params: WorkerParameters, private val repository: TarefasRepository, ) : CoroutineWorker(context, params) { override suspend fun doWork(): Result = try { repository.sincronizarPendentes() Result.success() } catch (e: IOException) { Result.retry() } catch (e: HttpException) { if (e.code() in 500..599) Result.retry() else Result.failure() } } Ao agendar, use restrições realistas:\nval request = OneTimeWorkRequestBuilder\u0026lt;SincronizarTarefasWorker\u0026gt;() .setConstraints( Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build() ) .setBackoffCriteria( BackoffPolicy.EXPONENTIAL, 30.seconds.toJavaDuration() ) .build() WorkManager.getInstance(context).enqueueUniqueWork( \u0026#34;sync-tarefas\u0026#34;, ExistingWorkPolicy.KEEP, request, ) Use ExistingWorkPolicy.KEEP quando não quiser disparar várias sincronizações idênticas. Use REPLACE apenas quando a nova execução realmente deve cancelar a anterior.\nEstratégias de conflito Conflito acontece quando o mesmo dado muda no dispositivo e no servidor antes da sincronização. Ignorar esse problema é pedir bug intermitente.\nAs estratégias mais comuns são:\nlast write wins: a alteração mais recente vence, simples mas perigosa; server wins: o servidor prevalece, bom para dados sensíveis ou controlados; client wins: o dispositivo prevalece, útil em rascunhos locais; merge por campo: cada campo tem regra própria; resolução manual: o usuário escolhe quando o conflito tem impacto real. Para muitos apps Android, uma combinação resolve bem: ações simples como “favoritar” usam last write wins; formulários importantes usam versão ou updatedAt; dados financeiros, médicos ou regulados devem favorecer o servidor e exibir mensagem clara. Mesmo este site não sendo YMYL, apps reais podem entrar em contextos sensíveis, então não trate sincronização como detalhe invisível quando a decisão afeta dinheiro, saúde ou segurança.\nEstado de tela: mostre a verdade sem assustar o usuário Offline-first não significa esconder tudo. O usuário precisa entender quando a ação foi salva localmente e quando ainda falta sincronizar.\nUm UiState pode carregar essa informação:\ndata class TarefasUiState( val tarefas: List\u0026lt;Tarefa\u0026gt; = emptyList(), val carregando: Boolean = true, val offline: Boolean = false, val pendentesSync: Int = 0, val mensagem: String? = null, ) Na interface, prefira mensagens úteis: “Alteração salva neste aparelho. Vamos sincronizar quando a conexão voltar.” Isso é melhor que um erro genérico. Para operações críticas, deixe claro se a ação ainda não chegou ao servidor.\nEsse cuidado conversa com Jetpack Compose porque estado explícito torna a UI previsível. Em Compose, a tela apenas renderiza o estado atual; o ViewModel combina fluxos de dados locais, conectividade e fila pendente.\nTestes que valem a pena Testar offline-first exige cobrir cenários que muitas equipes esquecem:\nusuário cria item sem internet; app fecha antes da sincronização; API retorna erro 500 e depois volta; servidor rejeita operação com 409 Conflict; migration preserva itens pendentes; WorkManager não dispara workers duplicados; tela mostra dados locais antes do refresh remoto. Use testes unitários no repository para regras de fila e testes instrumentados para Room quando necessário. Se o projeto já usa JUnit 5 e MockK, simule API indisponível e confirme que o banco local continua correto. Para organizar essa cobertura em camadas, consulte também o guia completo de testes em Kotlin, especialmente as partes de Flow, Android e CI.\nErros comuns em apps offline-first O erro mais comum é chamar tudo de cache. Cache pode ser descartável; dado offline-first não pode. Se o usuário criou um registro local, aquilo precisa de durabilidade, status e estratégia de retry.\nOutro erro é sincronizar tudo em uma única chamada gigante. Isso dificulta retry parcial, aumenta risco de conflito e deixa o app frágil. Prefira operações pequenas, idempotentes quando possível, com identificadores locais e remotos bem definidos.\nTambém evite espalhar lógica de rede pela UI. Quando cada tela decide se busca API, salva banco ou mostra cache, o comportamento fica inconsistente. Centralize no repository e faça a UI observar estado.\nPor fim, não esqueça observabilidade. Logs estruturados, métricas de falha de sync e contagem de operações pendentes ajudam a encontrar problemas reais em produção. Se o app depende de backend, vale estudar também observabilidade em Kotlin e CI/CD para Kotlin.\nQuando não usar offline-first completo? Nem todo app precisa do pacote inteiro. Um app de notícias pode resolver com cache de leitura e refresh manual. Um app bancário pode permitir consulta offline limitada, mas bloquear transações sem confirmação do servidor. Um app de entregas, por outro lado, provavelmente precisa fila local, geolocalização, retry e confirmação explícita.\nA pergunta prática é: o que o usuário precisa fazer quando a rede falha? Se a resposta for “continuar trabalhando”, offline-first merece arquitetura de primeira classe.\nConclusão Android offline-first com Kotlin é uma combinação madura em 2026. Room oferece persistência local reativa, DataStore resolve preferências pequenas, Retrofit com Kotlin organiza chamadas REST, WorkManager cuida de sincronização confiável, Flow mantém a UI atualizada e coroutines deixam o código assíncrono legível.\nO ponto mais importante é arquitetural: trate rede como detalhe instável, não como base da experiência. A tela deve depender do estado local; o repository deve coordenar banco, API e fila; a sincronização deve ser resiliente, observável e testável.\nSe você está montando portfólio, um app offline-first bem documentado vale muito mais que um CRUD que só funciona online. Ele demonstra maturidade de produto, conhecimento de Android real e capacidade de lidar com problemas que aparecem em produção. Para ampliar a visão além do mobile, vale comparar como Go é usado em backends leves que sincronizam dados com apps mobile. No Kotlin, a vantagem é construir a experiência Android e a camada de domínio com a mesma linguagem, mantendo segurança de tipos do banco local até a tela.\n","permalink":"https://kotlin.dev.br/blog/android-offline-first-kotlin-2026/","summary":"\u003cp\u003eConstruir um app Android que funciona bem apenas com internet perfeita é fácil. O desafio real aparece no ônibus, no elevador, no supermercado, no interior do Brasil, em redes corporativas instáveis ou quando o usuário abre o app com dados móveis fracos. É nesse cenário que a arquitetura \u003cstrong\u003eoffline-first com Kotlin\u003c/strong\u003e deixa de ser luxo técnico e vira requisito de produto. Como esse desenho aumenta o volume de dados no dispositivo, vale tratar \u003ca href=\"/blog/seguranca-dados-locais-android-kotlin-2026/\"\u003esegurança de dados locais no Android\u003c/a\u003e como parte da arquitetura desde o começo.\u003c/p\u003e","title":"Android Offline-First com Kotlin: Arquitetura em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA CI\u0026T busca uma pessoa Android Engineer Pleno para atuar em produtos AI-First, em modelo híbrido em Campinas, São Paulo.\nTecnologias e contextoKotlinAndroid Architecture ComponentsMVVM e Clean ArchitectureREST APIsAWSIoTRequisitosExperiência em desenvolvimento Android com Kotlin.Conhecimento em arquitetura Android, incluindo Android Architecture Components.Vivência com MVVM, Clean Architecture e integração com REST APIs.Disponibilidade para atuar em modelo híbrido em Campinas, São Paulo. ","permalink":"https://kotlin.dev.br/vagas/nvk2cccze6ft22e7-ci-t-android-engineer-pleno-produtos-ai-first/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T busca uma pessoa Android Engineer Pleno para atuar em produtos AI-First, em modelo híbrido em Campinas, São Paulo.\u003c/p\u003e\u003ch3\u003eTecnologias e contexto\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eAndroid Architecture Components\u003c/li\u003e\u003cli\u003eMVVM e Clean Architecture\u003c/li\u003e\u003cli\u003eREST APIs\u003c/li\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eIoT\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento Android com Kotlin.\u003c/li\u003e\u003cli\u003eConhecimento em arquitetura Android, incluindo Android Architecture Components.\u003c/li\u003e\u003cli\u003eVivência com MVVM, Clean Architecture e integração com REST APIs.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuar em modelo híbrido em Campinas, São Paulo.\u003c/li\u003e\u003c/ul\u003e","title":"Android Engineer Pleno – Produtos AI-First"},{"content":"Sobre a vagaA TechnipFMC busca uma pessoa Desenvolvedora de Software Sênior para atuação presencial no Rio de Janeiro, com foco em desenvolvimento de sistemas e soluções em cloud.\nResponsabilidadesDesenvolver, manter e evoluir aplicações e serviços de software.Trabalhar com APIs REST, bancos de dados e integrações entre sistemas.Atuar em ambientes cloud na AWS, incluindo serviços como S3, ECS, RDS, Lambda e SQS.Colaborar com práticas de versionamento, integração contínua e entrega contínua.RequisitosExperiência sênior em desenvolvimento de software.Conhecimento em Kotlin, Java, Python ou Go.Experiência com JavaScript, TypeScript e frameworks frontend como React, Angular ou Vue.js.Conhecimento em PostgreSQL, MongoDB, Docker, Git e GitHub.Familiaridade com CloudFormation, CI/CD e serviços AWS.Modelo de trabalhoVaga presencial no Rio de Janeiro, Rio de Janeiro, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/rk9964cbsm6ns4y6-technipfmc-desenvolvedor-de-software-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA TechnipFMC busca uma pessoa Desenvolvedora de Software Sênior para atuação presencial no Rio de Janeiro, com foco em desenvolvimento de sistemas e soluções em cloud.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver, manter e evoluir aplicações e serviços de software.\u003c/li\u003e\u003cli\u003eTrabalhar com APIs REST, bancos de dados e integrações entre sistemas.\u003c/li\u003e\u003cli\u003eAtuar em ambientes cloud na AWS, incluindo serviços como S3, ECS, RDS, Lambda e SQS.\u003c/li\u003e\u003cli\u003eColaborar com práticas de versionamento, integração contínua e entrega contínua.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento de software.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Java, Python ou Go.\u003c/li\u003e\u003cli\u003eExperiência com JavaScript, TypeScript e frameworks frontend como React, Angular ou Vue.js.\u003c/li\u003e\u003cli\u003eConhecimento em PostgreSQL, MongoDB, Docker, Git e GitHub.\u003c/li\u003e\u003cli\u003eFamiliaridade com CloudFormation, CI/CD e serviços AWS.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial no Rio de Janeiro, Rio de Janeiro, Brasil.\u003c/p\u003e","title":"Desenvolvedor de Software Sênior"},{"content":"Sobre a vagaA TechnipFMC busca uma pessoa Desenvolvedora de Software Sr para atuar presencialmente no Rio de Janeiro, Rio de Janeiro.\nRequisitos e tecnologiasExperiência em desenvolvimento de software em nível sênior.Conhecimento em Kotlin, Java, Python ou Go.Experiência com AWS, incluindo S3, ECS, Lambda, SQS, CloudFormation e Bedrock.Vivência com Docker, Git e GitHub.Conhecimento em bancos de dados PostgreSQL e MongoDB.Experiência com APIs REST.Conhecimento em tecnologias web como HTML5, CSS3, JavaScript, TypeScript, React, Angular ou Vue.js.Modelo de trabalhoVaga presencial no Rio de Janeiro.\n","permalink":"https://kotlin.dev.br/vagas/9zug5p3a894hqr5l-technipfmc-desenvolvedor-de-software-sr/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA TechnipFMC busca uma pessoa Desenvolvedora de Software Sr para atuar presencialmente no Rio de Janeiro, Rio de Janeiro.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento de software em nível sênior.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Java, Python ou Go.\u003c/li\u003e\u003cli\u003eExperiência com AWS, incluindo S3, ECS, Lambda, SQS, CloudFormation e Bedrock.\u003c/li\u003e\u003cli\u003eVivência com Docker, Git e GitHub.\u003c/li\u003e\u003cli\u003eConhecimento em bancos de dados PostgreSQL e MongoDB.\u003c/li\u003e\u003cli\u003eExperiência com APIs REST.\u003c/li\u003e\u003cli\u003eConhecimento em tecnologias web como HTML5, CSS3, JavaScript, TypeScript, React, Angular ou Vue.js.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial no Rio de Janeiro.\u003c/p\u003e","title":"Desenvolvedor de Software Sr"},{"content":"Sobre a vagaA Atoms busca uma pessoa Engenheira de Integrações de nível pleno para atuação presencial em São Paulo, São Paulo.\nStack informadaKotlinJavaGoC++C#Modelo de trabalhoVaga presencial em São Paulo, São Paulo.\n","permalink":"https://kotlin.dev.br/vagas/trl5t6wvv24c3yme-atoms-engenheiro-de-integracoes/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Atoms busca uma pessoa Engenheira de Integrações de nível pleno para atuação presencial em São Paulo, São Paulo.\u003c/p\u003e\u003ch3\u003eStack informada\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eGo\u003c/li\u003e\u003cli\u003eC++\u003c/li\u003e\u003cli\u003eC#\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em São Paulo, São Paulo.\u003c/p\u003e","title":"Engenheiro de Integrações"},{"content":"Sobre a vagaA CI\u0026amp;T busca uma pessoa Engenheira de IA / Desenvolvedora Master para atuação remota a partir de Campinas, São Paulo, Brasil.\nTecnologias mencionadasKotlin, Java, Android e iOSSwiftAWSClaude Code e SDDInformações da vagaEmpresa: CI\u0026amp;TNível informado: plenoModelo de trabalho: remotoLocalidade: Campinas, São Paulo, Brasil ","permalink":"https://kotlin.dev.br/vagas/ujkalhsl91qqgnsh-ci-t-engenheiro-a-de-ia-desenvolvedor-a-master/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026amp;T busca uma pessoa \u003cstrong\u003eEngenheira de IA / Desenvolvedora Master\u003c/strong\u003e para atuação remota a partir de Campinas, São Paulo, Brasil.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java, Android e iOS\u003c/li\u003e\u003cli\u003eSwift\u003c/li\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eClaude Code e SDD\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eInformações da vaga\u003c/h3\u003e\u003cul\u003e\u003cli\u003eEmpresa: CI\u0026amp;T\u003c/li\u003e\u003cli\u003eNível informado: pleno\u003c/li\u003e\u003cli\u003eModelo de trabalho: remoto\u003c/li\u003e\u003cli\u003eLocalidade: Campinas, São Paulo, Brasil\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de IA / Desenvolvedor(a) Master"},{"content":"Sobre a vagaA Toast busca uma pessoa Engenheira de Software Staff para atuar em nível sênior, em modelo híbrido, com base em Dublin ou São Paulo.\nStack técnicaKotlin e Java no backendReact, Tailwind e Storybook no frontendGraphQL para APIsAndroid para desenvolvimento mobilePostgreSQL e DynamoDB para dadosApache Pulsar, Apache Camel e RabbitMQ para mensageria e integraçãoModelo de trabalhoModelo híbridoLocalização: Dublin ou São PauloSenioridade: Staff / Sênior ","permalink":"https://kotlin.dev.br/vagas/hitfj7k1byiycdh1-toast-engenheiro-a-de-software-staff/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Toast busca uma pessoa Engenheira de Software Staff para atuar em nível sênior, em modelo híbrido, com base em Dublin ou São Paulo.\u003c/p\u003e\u003ch3\u003eStack técnica\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Java no backend\u003c/li\u003e\u003cli\u003eReact, Tailwind e Storybook no frontend\u003c/li\u003e\u003cli\u003eGraphQL para APIs\u003c/li\u003e\u003cli\u003eAndroid para desenvolvimento mobile\u003c/li\u003e\u003cli\u003ePostgreSQL e DynamoDB para dados\u003c/li\u003e\u003cli\u003eApache Pulsar, Apache Camel e RabbitMQ para mensageria e integração\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eModelo híbrido\u003c/li\u003e\u003cli\u003eLocalização: Dublin ou São Paulo\u003c/li\u003e\u003cli\u003eSenioridade: Staff / Sênior\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Staff"},{"content":"O Kotlin Multiplatform entrou em uma fase mais madura em 2026. A conversa deixou de ser apenas “dá para compartilhar código?” e passou a ser “como organizamos um produto real, com Android, iOS, web, desktop e backend, sem virar uma pasta gigante chamada composeApp?”.\nA mudança mais importante é a nova estrutura padrão de projetos KMP adotada pelos geradores e materiais recentes do ecossistema Kotlin. Em vez de concentrar aplicação, biblioteca compartilhada e configuração de plataformas no mesmo módulo, a recomendação agora separa responsabilidades: código compartilhado em um módulo claro, apps de entrada em módulos próprios e, quando necessário, divisão entre lógica e UI compartilhada.\nPara times brasileiros que estão saindo de um app Android nativo, avaliando Compose Multiplatform para iOS em produção ou comparando Kotlin Multiplatform com Flutter, essa mudança é prática. Ela ajuda a reduzir dívida de build, melhora onboarding e prepara o projeto para o Android Gradle Plugin 9.\nO que mudou na estrutura padrão Durante muito tempo, muitos exemplos de KMP com Compose usavam um módulo composeApp. Esse módulo acumulava várias responsabilidades:\nbiblioteca multiplataforma com código comum; aplicação Android; aplicação desktop ou web; configuração de recursos, empacotamento e dependências de UI; às vezes integração com o projeto iOS. Funcionava para demos e projetos pequenos, mas ficava confuso quando o produto crescia. Uma pessoa nova no time precisava descobrir se determinado arquivo era parte da biblioteca compartilhada, da aplicação Android, da UI comum ou apenas de uma configuração de empacotamento.\nA estrutura nova deixa a intenção explícita. Um ponto de partida comum fica assim:\nmeu-produto-kmp/ ├── shared/ # Biblioteca Kotlin Multiplatform │ └── src/ │ ├── commonMain/ │ ├── commonTest/ │ ├── androidMain/ │ ├── iosMain/ │ └── desktopMain/ ├── androidApp/ # Entrada Android ├── iosApp/ # Projeto iOS/Xcode ├── desktopApp/ # Entrada desktop, se existir ├── webApp/ # Entrada web, se existir └── settings.gradle.kts O módulo shared passa a ter uma responsabilidade simples: entregar uma biblioteca multiplataforma. Os módulos androidApp, iosApp, desktopApp e webApp são aplicações que consomem essa biblioteca.\nPor que isso importa para Android e AGP 9 O Android Gradle Plugin 9 reforça uma separação que já era saudável: a aplicação Android deve viver em um módulo próprio. Em projetos KMP antigos, era comum aplicar plugin de aplicação Android dentro do mesmo módulo multiplataforma que também carregava a lógica compartilhada. Essa abordagem cria acoplamento entre distribuição Android e biblioteca comum.\nCom a nova estrutura, o shared pode aplicar com.android.library, enquanto androidApp aplica com.android.application:\n// shared/build.gradle.kts plugins { kotlin(\u0026#34;multiplatform\u0026#34;) id(\u0026#34;com.android.library\u0026#34;) } kotlin { androidTarget() iosArm64() iosSimulatorArm64() sourceSets { commonMain.dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.0\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0\u0026#34;) } } } // androidApp/build.gradle.kts plugins { id(\u0026#34;com.android.application\u0026#34;) kotlin(\u0026#34;android\u0026#34;) } dependencies { implementation(project(\u0026#34;:shared\u0026#34;)) } Essa separação facilita CI, assinatura, flavors, Play Store, testes instrumentados e migração incremental. O time Android continua tendo um módulo de app reconhecível, enquanto o time multiplataforma trabalha na biblioteca compartilhada sem carregar toda a configuração de distribuição.\nQuando usar sharedLogic e sharedUI Nem todo projeto KMP compartilha interface. Muitos times brasileiros começam compartilhando apenas domínio, validações, modelos, clientes HTTP e casos de uso. Outros querem compartilhar telas com Compose Multiplatform. A estrutura nova acomoda os dois cenários.\nSe parte das plataformas usa UI nativa e parte usa Compose, separar sharedLogic e sharedUI costuma ser melhor:\nmeu-app/ ├── sharedLogic/ # Regras, modelos, networking, storage abstrato ├── sharedUI/ # Componentes Compose compartilhados ├── androidApp/ # Consome sharedLogic + sharedUI ├── iosApp/ # Pode consumir sharedLogic e usar SwiftUI └── desktopApp/ # Pode consumir sharedLogic + sharedUI Use sharedLogic para código que todas as plataformas precisam:\nmodelos de domínio; validações de formulário; regras de preço, elegibilidade ou permissões; clientes HTTP com Ktor Client; serialização; interfaces de repositório; casos de uso testáveis. Use sharedUI quando a plataforma realmente vai renderizar com Compose:\ncomponentes visuais compartilhados; design system multiplataforma; telas comuns entre Android, desktop e web; previews e testes de UI Compose quando fizer sentido. Em um banco, marketplace ou app de delivery no Brasil, essa divisão permite um caminho gradual: Android pode adotar Compose compartilhado primeiro, iOS pode manter SwiftUI, e a lógica de Pix, carrinho, autenticação ou catálogo continua unificada.\nEstrutura com backend Kotlin no mesmo produto Alguns projetos KMP também têm backend Kotlin. Isso é comum quando a equipe quer compartilhar modelos, validações e contratos entre app e servidor. Nesse caso, uma estrutura com core e server evita misturar código de cliente com API:\nproduto/ ├── core/ # Modelos e validações comuns a client/server ├── shared/ # Código compartilhado entre apps cliente ├── server/ # Ktor ou Spring Boot └── app/ ├── androidApp/ ├── iosApp/ └── webApp/ O core deve ser pequeno e conservador. Coloque ali apenas o que realmente precisa existir dos dois lados. Se o módulo vira um depósito de tudo, você troca duplicação por acoplamento.\nPara backend, o site já tem guias sobre Ktor, OpenAPI com Ktor e Kotlin server-side. A nova estrutura KMP combina bem com essa linha porque separa contrato, app e servidor desde cedo.\nComo migrar de composeApp sem quebrar tudo Não precisa reescrever o projeto em um fim de semana. A migração segura é incremental:\nMapeie responsabilidades atuais. Liste o que em composeApp é lógica compartilhada, UI compartilhada, app Android, desktop ou web. Crie o módulo shared. Mova primeiro modelos, casos de uso, clientes HTTP e testes comuns. Crie androidApp. Faça o app Android depender de shared e mova configurações específicas de aplicação. Mantenha iOS simples. Garanta que o framework gerado continue sendo consumido pelo projeto Xcode antes de mexer em UI. Extraia sharedUI só se houver necessidade real. Não crie módulo visual compartilhado se iOS continuará 100% nativo. Atualize CI por módulo. Rode build e testes por partes para saber onde a quebra aconteceu. Uma migração mínima pode começar apenas movendo domínio para shared e deixando o restante como está. O ganho imediato é deixar claro o que é biblioteca multiplataforma e o que é aplicação.\nChecklist para projetos novos em 2026 Se você está criando um projeto KMP agora, use este checklist:\nshared é biblioteca, não aplicação; androidApp aplica com.android.application; iosApp fica explícito e documentado para quem usa Xcode; commonMain não importa API Android, UIKit ou JVM sem abstração; commonTest cobre regras de negócio antes de UI; dependências ficam próximas do módulo que as usa; settings.gradle.kts mostra a arquitetura com nomes claros; CI roda pelo menos :shared:allTests e build do app Android; versões de Kotlin, Compose, AGP e Ktor ficam centralizadas em version catalog quando o projeto crescer. Para quem ainda está aprendendo, comece pelo guia de Kotlin Multiplatform e pelo tutorial de Kotlin Multiplatform. Para decisão de produto, compare também KMP vs React Native e KMP vs Flutter.\nErros comuns na adoção O erro mais comum é transformar shared em uma camada “global” onde tudo entra. KMP funciona melhor quando o módulo compartilhado tem limites. Se uma regra só existe no Android, ela deve ficar no Android. Se uma tela só existe no iOS, não force Compose compartilhado.\nOutro erro é migrar UI e lógica ao mesmo tempo. Para times que já têm app em produção, normalmente vale compartilhar lógica primeiro. Depois, componentes Compose podem entrar em telas novas, fluxos internos ou áreas onde a paridade visual entre plataformas compensa.\nTambém evite copiar estruturas de exemplo sem olhar o contexto. Um app com Android e iOS nativo não precisa da mesma organização de um produto com Android, iOS, desktop, web e backend. A nova estrutura não é uma árvore obrigatória; é um conjunto de princípios: responsabilidade clara, entradas separadas e compartilhamento explícito.\nConclusão A nova estrutura padrão do Kotlin Multiplatform em 2026 é menos sobre nomes de pastas e mais sobre maturidade. Separar shared, androidApp, iosApp e módulos opcionais de UI deixa o projeto mais previsível, especialmente para equipes que precisam evoluir produto, CI, publicação e onboarding ao mesmo tempo.\nPara projetos brasileiros, o ganho é direto: dá para adotar KMP sem pedir que todo mundo mude de ferramenta no mesmo dia. Android continua com seu módulo, iOS continua com Xcode quando necessário, backend Kotlin pode compartilhar contratos com cuidado, e a lógica comum fica testável em um lugar claro.\nSe você está começando um app novo, já comece com módulos separados. Se está migrando um projeto antigo com composeApp, faça a extração em etapas: lógica primeiro, aplicação Android em módulo próprio, UI compartilhada apenas quando ela realmente pagar a conta.\n","permalink":"https://kotlin.dev.br/blog/kmp-nova-estrutura-projetos-2026/","summary":"\u003cp\u003eO Kotlin Multiplatform entrou em uma fase mais madura em 2026. A conversa deixou de ser apenas “dá para compartilhar código?” e passou a ser “como organizamos um produto real, com Android, iOS, web, desktop e backend, sem virar uma pasta gigante chamada \u003ccode\u003ecomposeApp\u003c/code\u003e?”.\u003c/p\u003e\n\u003cp\u003eA mudança mais importante é a \u003cstrong\u003enova estrutura padrão de projetos KMP\u003c/strong\u003e adotada pelos geradores e materiais recentes do ecossistema Kotlin. Em vez de concentrar aplicação, biblioteca compartilhada e configuração de plataformas no mesmo módulo, a recomendação agora separa responsabilidades: código compartilhado em um módulo claro, apps de entrada em módulos próprios e, quando necessário, divisão entre lógica e UI compartilhada.\u003c/p\u003e","title":"KMP em 2026: Nova Estrutura de Projeto para Apps Multiplataforma"},{"content":"Documentar uma API Ktor com OpenAPI não é burocracia: é uma forma de transformar rotas, DTOs, códigos de status e regras de autenticação em um contrato que frontend, mobile, QA e integrações externas conseguem consultar sem adivinhar o comportamento do backend. Em times pequenos, isso evita mensagens soltas no chat. Em times maiores, vira base para SDKs, testes de contrato e versionamento.\nEste tutorial mostra um caminho prático para usar Swagger UI e OpenAPI em Ktor sem perder o estilo idiomático do Kotlin. A ideia é começar com um contrato simples, expor uma documentação navegável, manter exemplos úteis e conectar o tema com o que você já usa em REST APIs com Kotlin, Ktor para backend e testes automatizados.\nQuando vale documentar uma API Ktor com OpenAPI? Vale documentar quando a API tem mais de um consumidor, quando uma pessoa nova precisa entender o contrato rapidamente ou quando mudanças de resposta podem quebrar outro sistema. Mesmo em um projeto de portfólio, uma página Swagger bem feita passa uma mensagem forte: você sabe construir backend pensando em consumo real, não apenas em rotas que funcionam localmente.\nOs sinais de que OpenAPI deve entrar no projeto são claros:\no app Android, web ou serviço parceiro consome a API; existem endpoints privados e públicos com autenticação diferente; DTOs mudam com frequência e precisam de exemplos; QA precisa saber quais erros esperar; você quer gerar clientes HTTP ou validar contrato em CI; há vagas ou entrevistas pedindo experiência com APIs documentadas. Se o projeto ainda está no começo, não espere “ficar grande” para documentar. Um contrato pequeno e atualizado é melhor que uma documentação enorme escrita depois, quando ninguém lembra por que cada endpoint existe.\nModelo mental: contrato primeiro, implementação sempre perto OpenAPI descreve a superfície HTTP da sua aplicação: caminhos, métodos, parâmetros, corpo de requisição, respostas, schemas, autenticação e metadados. O erro comum é tratar o arquivo openapi.yaml como um artefato separado que envelhece longe do código.\nNo Ktor, pense em três camadas:\nrotas Ktor definem o comportamento real; DTOs Kotlin representam entrada e saída; contrato OpenAPI explica como consumidores devem chamar a API. O objetivo é manter essas três camadas próximas. Se você usa geração automática disponível na versão do seu stack, ótimo. Se ainda mantém YAML manual, coloque o arquivo no repositório, revise junto do código e valide no pipeline. O ponto não é a ferramenta perfeita; é impedir que contrato e implementação se contradigam.\nDependências básicas para Swagger UI em Ktor O ecossistema Ktor permite diferentes abordagens. Em muitos projetos, você verá uma combinação de plugin de OpenAPI/Swagger, arquivo YAML servido pela aplicação e uma rota de interface visual. O exemplo abaixo usa uma estrutura didática: mantenha openapi/documentation.yaml como fonte do contrato e exponha Swagger UI em /swagger.\n// build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.3.20\u0026#34; id(\u0026#34;io.ktor.plugin\u0026#34;) version \u0026#34;3.4.0\u0026#34; kotlin(\u0026#34;plugin.serialization\u0026#34;) version \u0026#34;2.3.20\u0026#34; } repositories { mavenCentral() } dependencies { implementation(\u0026#34;io.ktor:ktor-server-core-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-netty-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-content-negotiation-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-serialization-kotlinx-json-jvm\u0026#34;) // Use os artefatos de OpenAPI/Swagger compatíveis com a sua versão do Ktor. implementation(\u0026#34;io.ktor:ktor-server-openapi\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-swagger\u0026#34;) testImplementation(\u0026#34;io.ktor:ktor-server-tests-jvm\u0026#34;) testImplementation(\u0026#34;org.jetbrains.kotlin:kotlin-test-junit\u0026#34;) } Antes de copiar versões para produção, confira a documentação oficial e a versão usada pelo seu projeto. Se você está migrando de Ktor 2.x para Ktor 3.x, leia também o resumo de Ktor 3.4 com OpenAPI e streaming para entender o que mudou no suporte de documentação.\nCriando uma API de exemplo Vamos usar uma API de tarefas porque ela é pequena o bastante para caber em um tutorial, mas real o suficiente para demonstrar listagem, criação, erros e autenticação futura.\nimport kotlinx.serialization.Serializable @Serializable data class TarefaResponse( val id: Long, val titulo: String, val concluida: Boolean ) @Serializable data class CriarTarefaRequest( val titulo: String ) @Serializable data class ErroResponse( val codigo: String, val mensagem: String ) A rota Ktor pode começar simples:\nimport io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* fun Application.tarefaRoutes() { val tarefas = mutableListOf( TarefaResponse(1, \u0026#34;Documentar API Ktor\u0026#34;, false) ) routing { route(\u0026#34;/api/v1/tarefas\u0026#34;) { get { call.respond(tarefas) } post { val request = call.receive\u0026lt;CriarTarefaRequest\u0026gt;() if (request.titulo.isBlank()) { call.respond( HttpStatusCode.BadRequest, ErroResponse( codigo = \u0026#34;titulo_obrigatorio\u0026#34;, mensagem = \u0026#34;Informe um título para a tarefa.\u0026#34; ) ) return@post } val nova = TarefaResponse( id = tarefas.size.toLong() + 1, titulo = request.titulo, concluida = false ) tarefas += nova call.respond(HttpStatusCode.Created, nova) } } } } Essa implementação é propositalmente simples. Em uma aplicação real, você provavelmente teria service, repository, banco de dados com Exposed ou outro mecanismo de persistência, além de validação mais completa. O contrato OpenAPI precisa refletir o comportamento observável, não a organização interna.\nEscrevendo o primeiro openapi.yaml Crie um arquivo como src/main/resources/openapi/documentation.yaml. Ele deve começar com metadados claros e schemas pequenos.\nopenapi: 3.1.0 info: title: API de Tarefas Kotlin Brasil version: 1.0.0 description: API de exemplo construída com Ktor e Kotlin. servers: - url: https://api.exemplo.com description: Produção - url: http://localhost:8080 description: Desenvolvimento local paths: /api/v1/tarefas: get: summary: Lista tarefas operationId: listarTarefas tags: [Tarefas] responses: \u0026#34;200\u0026#34;: description: Lista de tarefas retornada com sucesso. content: application/json: schema: type: array items: $ref: \u0026#34;#/components/schemas/TarefaResponse\u0026#34; examples: exemplo: value: - id: 1 titulo: Documentar API Ktor concluida: false post: summary: Cria uma tarefa operationId: criarTarefa tags: [Tarefas] requestBody: required: true content: application/json: schema: $ref: \u0026#34;#/components/schemas/CriarTarefaRequest\u0026#34; responses: \u0026#34;201\u0026#34;: description: Tarefa criada. content: application/json: schema: $ref: \u0026#34;#/components/schemas/TarefaResponse\u0026#34; \u0026#34;400\u0026#34;: description: Requisição inválida. content: application/json: schema: $ref: \u0026#34;#/components/schemas/ErroResponse\u0026#34; components: schemas: CriarTarefaRequest: type: object required: [titulo] properties: titulo: type: string minLength: 1 example: Revisar contrato OpenAPI TarefaResponse: type: object required: [id, titulo, concluida] properties: id: type: integer format: int64 example: 1 titulo: type: string example: Documentar API Ktor concluida: type: boolean example: false ErroResponse: type: object required: [codigo, mensagem] properties: codigo: type: string example: titulo_obrigatorio mensagem: type: string example: Informe um título para a tarefa. Esse YAML já entrega valor: qualquer pessoa consegue abrir o contrato e entender como listar e criar tarefas. Repare que os exemplos não são enfeite. Eles ajudam consumidores a saber formato, nomes de campos, tipos e respostas esperadas.\nExpondo Swagger UI no Ktor Com o contrato dentro de resources, exponha uma rota para a documentação. O formato exato pode variar conforme a versão do Ktor e o plugin escolhido, mas a ideia é esta:\nimport io.ktor.server.application.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* import io.ktor.server.plugins.swagger.* import io.ktor.server.routing.* fun Application.module() { install(ContentNegotiation) { json() } tarefaRoutes() routing { swaggerUI( path = \u0026#34;swagger\u0026#34;, swaggerFile = \u0026#34;openapi/documentation.yaml\u0026#34; ) } } Depois de subir a aplicação, acesse http://localhost:8080/swagger. A interface deve mostrar os endpoints, schemas e exemplos definidos no contrato.\nSe você preferir servir apenas o JSON ou YAML para uma ferramenta externa, exponha um endpoint como /openapi.yaml e publique a UI em outro lugar. O importante é que o contrato esteja disponível no mesmo ciclo de deploy da API.\nDocumentando erros e autenticação Um contrato útil não mostra apenas o caminho feliz. Ele documenta erros comuns, códigos de status e regras de autenticação. Para APIs com JWT, adicione um security scheme:\ncomponents: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT security: - bearerAuth: [] Em endpoints públicos, você pode sobrescrever com security: []. Em endpoints privados, declare respostas como 401 e 403 com payload de erro. Isso evita uma frustração comum: o frontend descobrir em runtime que a API retorna um formato de erro diferente em cada rota.\nPara Ktor, alinhe o contrato com o bloco de autenticação:\nimport io.ktor.server.auth.* import io.ktor.server.routing.* fun Application.rotasPrivadas() { routing { authenticate(\u0026#34;auth-jwt\u0026#34;) { get(\u0026#34;/api/v1/perfil\u0026#34;) { // resposta do perfil autenticado } } } } Se a rota está dentro de authenticate, o OpenAPI deve deixar isso explícito. Se a rota aceita chamadas anônimas, não marque como protegida por acidente.\nMantendo DTOs e schemas sincronizados O maior risco de OpenAPI manual é divergência. Para reduzir isso, crie uma rotina simples:\ntoda PR que muda request ou response precisa alterar o contrato; exemplos devem ser atualizados junto com os DTOs; códigos de erro precisam ter nome estável; campos removidos devem ser tratados como breaking change; o pipeline deve validar o YAML. Você pode usar ferramentas como swagger-cli, redocly, spectral ou geradores de cliente em CI. Mesmo que não gere código, validar o arquivo já captura indentação quebrada, $ref inválido e schemas incompletos.\nUm teste simples no projeto também ajuda:\nimport kotlin.test.Test import kotlin.test.assertTrue class OpenApiContractTest { @Test fun `contrato openapi deve existir no classpath`() { val resource = javaClass.classLoader .getResource(\u0026#34;openapi/documentation.yaml\u0026#34;) assertTrue(resource != null, \u0026#34;Contrato OpenAPI não encontrado\u0026#34;) } } Esse teste não valida todo o contrato, mas evita o erro básico de esquecer o arquivo fora do pacote final. Para validação forte, combine com uma ferramenta especializada no pipeline de CI/CD para Kotlin.\nVersionamento de API e contrato Versionar API não é apenas colocar /v1 na URL. O contrato deve indicar a versão do documento, e mudanças incompatíveis precisam de cuidado. Exemplos de breaking changes:\nremover campo de resposta usado por clientes; mudar tipo de id de número para string; tornar obrigatório um campo antes opcional; alterar o formato de erro; trocar códigos HTTP sem compatibilidade. Mudanças aditivas geralmente são seguras: adicionar campo opcional, novo endpoint, novo valor em enum documentado como extensível. Em Kotlin, prefira DTOs explícitos de request e response em vez de expor entidades internas diretamente. Isso facilita evoluir o banco sem quebrar contrato público.\nChecklist para uma documentação Ktor que ajuda de verdade Antes de considerar sua documentação pronta, passe por este checklist:\na página Swagger abre em ambiente local; cada endpoint tem summary, operationId e tag; requests têm exemplos realistas; respostas de sucesso e erro estão documentadas; autenticação está clara; campos obrigatórios e opcionais estão corretos; DTOs não expõem senha, token interno ou detalhes de banco; o contrato passa em validação automatizada; a documentação é atualizada no mesmo commit da mudança de rota. Esse nível de disciplina já coloca seu projeto acima da média de muitos backends de portfólio.\nErros comuns ao usar Swagger com Ktor 1. Documentar só 200 OK. APIs reais falham. Mostre 400, 401, 403, 404, 409 e 500 quando fizer sentido.\n2. Copiar DTO interno para o contrato. Entidades de banco e DTOs públicos têm responsabilidades diferentes. O contrato deve representar o que o consumidor pode depender.\n3. Deixar exemplos genéricos demais. string e example vazio não ajudam. Use dados parecidos com o domínio real.\n4. Esquecer autenticação por rota. Uma UI Swagger linda não resolve nada se o consumidor não sabe quando enviar bearer token.\n5. Não validar em CI. YAML quebrado geralmente só aparece quando alguém tenta abrir a documentação. Valide antes do deploy.\nPróximos passos Depois que a documentação estiver funcionando, evolua para testes de contrato e geração de cliente. Um app Android, por exemplo, pode usar um cliente gerado ou pelo menos validar que os modelos esperados batem com o contrato publicado. Para backend, combine OpenAPI com testes em Kotlin, observabilidade e Docker para fechar o ciclo profissional.\nSe seu foco é comparar stacks, vale ver como a documentação de APIs aparece em FastAPI e Django REST em Python e em frameworks Go para APIs. O vocabulário muda, mas a responsabilidade é a mesma: contrato claro, exemplos úteis e mudança controlada.\nFAQ rápido Ktor gera OpenAPI automaticamente? Depende da versão e dos plugins usados no projeto. O suporte evoluiu bastante, mas muitos times ainda mantêm um openapi.yaml revisado junto do código. O melhor caminho é escolher uma abordagem que seu time consiga manter sem deixar a documentação envelhecer.\nSwagger UI deve ficar público em produção? Depende do produto. Para API pública, normalmente sim. Para API interna, você pode proteger a rota, expor apenas na intranet ou publicar a documentação em um portal separado. Nunca exponha endpoints administrativos ou exemplos com dados sensíveis.\nOpenAPI substitui testes? Não. OpenAPI descreve o contrato esperado. Testes verificam se a implementação cumpre esse contrato. O ideal é usar os dois: documentação para consumo humano e validação automatizada para evitar regressões.\nPreciso usar annotations? Não necessariamente. Uma vantagem do Kotlin com Ktor é manter rotas em DSL. Você pode documentar por YAML, por DSL de documentação ou por plugins que aproximam contrato e rota. Evite escolher uma solução apenas porque parece “mais automática”; escolha a que fica sustentável no repositório.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-ktor-openapi-swagger/","summary":"\u003cp\u003eDocumentar uma API Ktor com \u003cstrong\u003eOpenAPI\u003c/strong\u003e não é burocracia: é uma forma de transformar rotas, DTOs, códigos de status e regras de autenticação em um contrato que frontend, mobile, QA e integrações externas conseguem consultar sem adivinhar o comportamento do backend. Em times pequenos, isso evita mensagens soltas no chat. Em times maiores, vira base para SDKs, testes de contrato e versionamento.\u003c/p\u003e\n\u003cp\u003eEste tutorial mostra um caminho prático para usar \u003cstrong\u003eSwagger UI e OpenAPI em Ktor\u003c/strong\u003e sem perder o estilo idiomático do Kotlin. A ideia é começar com um contrato simples, expor uma documentação navegável, manter exemplos úteis e conectar o tema com o que você já usa em \u003ca href=\"/guias/guia-kotlin-rest-api/\"\u003eREST APIs com Kotlin\u003c/a\u003e, \u003ca href=\"/guias/guia-kotlin-backend-ktor/\"\u003eKtor para backend\u003c/a\u003e e \u003ca href=\"/guias/guia-testes-kotlin/\"\u003etestes automatizados\u003c/a\u003e.\u003c/p\u003e","title":"OpenAPI e Swagger no Ktor: Documente APIs Kotlin | Kotlin Brasil"},{"content":"O Model Context Protocol (MCP) entrou no radar de muitos times porque resolve um problema prático: como conectar agentes de IA a ferramentas reais sem criar uma integração improvisada para cada modelo, cada produto e cada sistema interno. Em vez de esconder tudo atrás de prompts enormes ou copiar dados manualmente para um chat, o MCP define uma forma padronizada de expor recursos, prompts e ferramentas que um agente pode descobrir e chamar.\nPara quem trabalha com Kotlin, a oportunidade é boa. A linguagem já é forte em backend, tem interoperabilidade madura com o ecossistema Java, lida bem com concorrência via coroutines e combina naturalmente com servidores leves em Ktor. Isso torna Kotlin uma escolha confortável para criar bridges entre sistemas internos, APIs corporativas e clientes de IA.\nEste guia explica como pensar em MCP com Kotlin em 2026: arquitetura, transporte, modelagem de ferramentas, segurança, observabilidade e um esqueleto de implementação com Ktor. A ideia não é vender hype; é mostrar onde o protocolo realmente ajuda e onde um endpoint REST comum continua sendo suficiente.\nO que MCP resolve na prática Um agente de IA útil precisa acessar contexto e executar ações. Em um ambiente de desenvolvimento, isso pode significar ler issues, consultar documentação, abrir pull requests, rodar testes ou buscar logs. Em uma empresa, pode significar consultar CRM, gerar relatórios, procurar contratos, acionar workflows internos ou validar dados em sistemas legados.\nSem um padrão, cada integração vira uma solução própria: um plugin específico para uma ferramenta, um wrapper para outro modelo, um endpoint com payload diferente, permissões espalhadas e documentação difícil de manter. O MCP tenta organizar essa camada.\nEm termos simples, um servidor MCP expõe três tipos principais de capacidade:\nresources, para dados que o agente pode ler; tools, para ações que o agente pode executar; prompts, para templates reutilizáveis de interação. O cliente conversa com o servidor usando mensagens estruturadas. O agente descobre o que existe, escolhe uma ferramenta e envia argumentos explícitos. O servidor valida, executa e devolve uma resposta também estruturada.\nPor que Kotlin é uma boa opção Kotlin não é a linguagem mais comum no ecossistema inicial de IA, onde Python domina bibliotecas, notebooks e prototipagem. Mesmo assim, Kotlin tem vantagens relevantes quando a integração precisa rodar em produção.\nPrimeiro, muitos sistemas corporativos já vivem na JVM. Se a empresa usa Spring Boot, Ktor, Kafka, bancos relacionais, filas, OpenTelemetry e bibliotecas Java, expor ferramentas MCP em Kotlin evita criar uma stack paralela só para IA. Segundo, Kotlin favorece modelagem explícita: data class, tipos anuláveis, sealed classes e serialização deixam contratos mais legíveis. Terceiro, coroutines ajudam a lidar com chamadas de rede, timeouts e streaming sem transformar o código em callbacks.\nEm produtos que já usam Kotlin para backend, MCP pode ser mais uma interface em cima da aplicação, não um serviço alienígena escrito às pressas em outra linguagem.\nArquitetura de um servidor MCP com Ktor Um servidor MCP em Kotlin pode começar pequeno. A estrutura conceitual costuma ter quatro camadas:\nTransporte, responsável por receber mensagens do cliente. Roteamento MCP, que identifica métodos como listagem de tools e execução. Catálogo de ferramentas, onde cada tool declara nome, descrição, schema de entrada e função de execução. Camada de domínio, que chama APIs, bancos, filas ou serviços internos. Com Ktor, o transporte pode ser HTTP. Dependendo do cliente e do padrão suportado, você pode trabalhar com requisições JSON, streaming via Server-Sent Events ou um processo local usando stdio. Para aplicações web e ambientes corporativos, HTTP tende a ser mais fácil de observar, autenticar e colocar atrás de um gateway.\nUm esqueleto simplificado ficaria assim:\nimport io.ktor.server.application.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* import kotlinx.serialization.Serializable @Serializable data class JsonRpcRequest( val jsonrpc: String = \u0026#34;2.0\u0026#34;, val id: String? = null, val method: String, val params: Map\u0026lt;String, String\u0026gt; = emptyMap() ) @Serializable data class JsonRpcResponse( val jsonrpc: String = \u0026#34;2.0\u0026#34;, val id: String? = null, val result: String? = null, val error: String? = null ) fun Application.mcpModule(toolRegistry: ToolRegistry) { routing { post(\u0026#34;/mcp\u0026#34;) { val request = call.receive\u0026lt;JsonRpcRequest\u0026gt;() val response = when (request.method) { \u0026#34;tools/list\u0026#34; -\u0026gt; JsonRpcResponse( id = request.id, result = toolRegistry.describeTools() ) \u0026#34;tools/call\u0026#34; -\u0026gt; JsonRpcResponse( id = request.id, result = toolRegistry.call(request.params) ) else -\u0026gt; JsonRpcResponse( id = request.id, error = \u0026#34;Método MCP não suportado: ${request.method}\u0026#34; ) } call.respond(response) } } } Esse exemplo é propositalmente pequeno. Em produção, você modelaria params como JSON estruturado, usaria kotlinx.serialization.json.JsonElement, teria erros padronizados de JSON-RPC e separaria transporte de protocolo. Ainda assim, o desenho mostra a ideia principal: Ktor recebe a mensagem, o registry descobre ou executa ferramentas, e o servidor devolve uma resposta previsível.\nModelando tools com contratos claros O ponto mais importante de um servidor MCP não é o endpoint; é a qualidade das ferramentas expostas. Uma tool ruim permite ações ambíguas, argumentos livres demais e efeitos colaterais perigosos. Uma tool boa tem nome específico, descrição operacional e schema de entrada restrito.\nCompare estes dois nomes:\nrun_action buscar_vagas_kotlin O segundo é muito melhor. Ele diz o que faz, reduz espaço para interpretação e facilita auditoria. O mesmo vale para argumentos. Em vez de aceitar uma string genérica chamada query, prefira campos explícitos quando possível:\n@Serializable data class BuscarVagasKotlinInput( val cidade: String? = null, val remoto: Boolean = true, val senioridade: Senioridade? = null, val limite: Int = 10 ) @Serializable enum class Senioridade { JUNIOR, PLENO, SENIOR } Essa modelagem é natural em Kotlin. Você ganha validação, documentação implícita e menos chance de um agente chamar a ferramenta de um jeito inesperado. Para conteúdos de carreira, por exemplo, essa abordagem conversa bem com páginas como como conseguir emprego Kotlin e portfólio para desenvolvedor Kotlin, porque transforma orientação editorial em fluxos práticos.\nSegurança: tools não são brinquedo Um erro comum em projetos de IA é tratar ferramenta como se fosse apenas mais uma resposta de texto. Não é. Tool executa ação. Ela pode consultar dados sensíveis, alterar registros, disparar mensagens, consumir crédito de API ou quebrar um deploy.\nPara um servidor MCP em Kotlin, algumas regras deveriam ser padrão:\nautenticar todo cliente; usar escopos por ferramenta; registrar auditoria de cada chamada; validar argumentos antes de executar; limitar tamanho de resposta; aplicar timeout em chamadas externas; separar tools somente leitura de tools com escrita; exigir aprovação humana para ações destrutivas. Ktor facilita essa separação com plugins de autenticação, interceptors e middlewares. Em sistemas maiores, vale integrar com o mesmo IAM usado pelo backend principal. Se a aplicação já tem roles para administradores, suporte e usuários internos, não crie uma permissão paralela mal documentada só para o MCP.\nTambém é importante não vazar contexto demais. Um resource que retorna “todos os contratos do cliente” provavelmente está amplo demais. Melhor criar recursos específicos: resumo permitido, campos mascarados, paginação, filtros obrigatórios e logs de acesso.\nCoroutines, timeouts e cancelamento MCP tende a chamar várias APIs. Uma tool pode buscar dados no banco, consultar uma API externa e montar uma resposta. Em Kotlin, coroutines ajudam, mas precisam ser usadas com disciplina.\nUse withTimeout para evitar tools presas indefinidamente:\nimport kotlinx.coroutines.withTimeout suspend fun consultarRelatorio(id: String): RelatorioResumo = withTimeout(5_000) { repositorio.buscarResumo(id) } Se a tool combina fontes independentes, coroutineScope e async podem reduzir latência. Mas não exagere: paralelismo sem limite pode derrubar dependências internas. Para consumidores assíncronos e integrações mais pesadas, vale estudar também padrões de mensageria com Kafka e RabbitMQ e structured concurrency.\nO princípio é simples: uma chamada MCP deve ser previsível. Se uma ação demora minutos, talvez ela não deva rodar síncrona. A tool pode criar um job, devolver um identificador e permitir consulta posterior de status.\nObservabilidade para integrações de IA Quando um agente chama uma tool errada, a pergunta operacional é: o problema foi prompt, permissão, schema, bug no servidor ou dado ruim? Sem observabilidade, você só vê “a IA errou”.\nInstrumente o servidor MCP como qualquer backend:\nlogs estruturados por toolName, requestId, usuário e duração; métricas de taxa de erro por ferramenta; tracing para chamadas externas; contadores de timeout; amostragem de payloads não sensíveis para depuração; alertas quando uma tool crítica começa a falhar. Se o projeto já usa observabilidade em Kotlin ou ferramentas como OpenTelemetry, o MCP deve entrar no mesmo pipeline. Essa é outra vantagem de usar Kotlin no backend: você reaproveita a disciplina de produção que já existe no time.\nQuando não usar MCP MCP não deve virar resposta automática para qualquer integração. Se o seu produto só precisa de um endpoint interno chamado por uma aplicação conhecida, REST ou gRPC podem ser mais simples. Se a operação é puramente batch, uma fila pode resolver melhor. Se o time ainda não sabe qual problema quer automatizar, criar um servidor MCP antes de mapear casos de uso é teatro tecnológico.\nUse MCP quando há agentes ou clientes de IA que precisam descobrir capacidades, alternar ferramentas e trabalhar com contexto externo de forma padronizada. Para APIs tradicionais entre serviços, continue usando as ferramentas tradicionais. O valor do protocolo aparece quando a interface é para agentes, não apenas para outro microserviço.\nTambém vale comparar com outras stacks. Go pode ser excelente para servidores pequenos e binários simples. Python pode acelerar protótipos de IA. Kotlin brilha quando o MCP precisa ficar perto de sistemas JVM, regras de domínio ricas e backend já existente.\nCaminho recomendado para começar Um roteiro realista para um time Kotlin:\nEscolha um caso de uso somente leitura, como consultar status de deploy, buscar documentação interna ou listar vagas. Modele uma única tool com input tipado e resposta pequena. Rode localmente com logs detalhados. Adicione autenticação e escopos antes de expor para qualquer agente real. Crie testes de contrato para o schema da tool. Meça latência, erros e chamadas por usuário. Só depois adicione tools com efeitos colaterais. Essa progressão evita o erro clássico de criar dez ferramentas frágeis de uma vez. O melhor servidor MCP é pequeno, confiável e fácil de auditar.\nConclusão MCP é uma peça importante para a próxima fase de agentes de IA, mas não muda os fundamentos de engenharia. Você ainda precisa de contratos claros, autenticação, logs, testes, timeouts, revisão de permissões e boas decisões de arquitetura. A diferença é que agora essas práticas precisam considerar agentes como consumidores diretos das suas ferramentas.\nKotlin com Ktor oferece uma base forte para esse trabalho. A stack é leve o bastante para criar servidores dedicados, madura o bastante para produção e expressiva o bastante para modelar tools com segurança. Para times que já usam Kotlin em Android, backend ou Kotlin Multiplatform, construir uma ponte MCP em Kotlin pode reduzir atrito e manter a inteligência artificial perto do domínio real do produto.\nComece por uma tool pequena. Valide o contrato. Observe cada chamada. Depois expanda. Em integração de IA, a vantagem não está em expor tudo rapidamente; está em expor o suficiente com confiança.\n","permalink":"https://kotlin.dev.br/blog/mcp-kotlin-ktor-agentes-ia-2026/","summary":"\u003cp\u003eO \u003cstrong\u003eModel Context Protocol (MCP)\u003c/strong\u003e entrou no radar de muitos times porque resolve um problema prático: como conectar agentes de IA a ferramentas reais sem criar uma integração improvisada para cada modelo, cada produto e cada sistema interno. Em vez de esconder tudo atrás de prompts enormes ou copiar dados manualmente para um chat, o MCP define uma forma padronizada de expor recursos, prompts e ferramentas que um agente pode descobrir e chamar.\u003c/p\u003e","title":"MCP em Kotlin com Ktor: Integrações para Agentes de IA em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA CI\u0026amp;T busca uma pessoa Desenvolvedora iOS Sênior para atuação remota na Colômbia, em projetos mobile com integração ao ecossistema Android/Kotlin.\nResponsabilidadesDesenvolver e manter aplicações iOS com foco em qualidade, estabilidade e evolução contínua.Colaborar com times mobile, produto e engenharia em entregas ponta a ponta.Trabalhar com pipelines de CI/CD e práticas modernas de desenvolvimento.Apoiar integrações com ferramentas de analytics e atribuição.RequisitosExperiência sênior em desenvolvimento iOS.Conhecimento em Objective-C.Experiência com Google Analytics, Appsflyer ou Segment.Vivência com CI/CD.Familiaridade com ambientes mobile que envolvem Android e Kotlin.DiferenciaisExperiência com ferramentas de IA aplicadas ao desenvolvimento de software. ","permalink":"https://kotlin.dev.br/vagas/f2tdz629s7cygwal-ci-t-desenvolvedor-a-ios-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026amp;T busca uma pessoa Desenvolvedora iOS Sênior para atuação remota na Colômbia, em projetos mobile com integração ao ecossistema Android/Kotlin.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações iOS com foco em qualidade, estabilidade e evolução contínua.\u003c/li\u003e\u003cli\u003eColaborar com times mobile, produto e engenharia em entregas ponta a ponta.\u003c/li\u003e\u003cli\u003eTrabalhar com pipelines de CI/CD e práticas modernas de desenvolvimento.\u003c/li\u003e\u003cli\u003eApoiar integrações com ferramentas de analytics e atribuição.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento iOS.\u003c/li\u003e\u003cli\u003eConhecimento em Objective-C.\u003c/li\u003e\u003cli\u003eExperiência com Google Analytics, Appsflyer ou Segment.\u003c/li\u003e\u003cli\u003eVivência com CI/CD.\u003c/li\u003e\u003cli\u003eFamiliaridade com ambientes mobile que envolvem Android e Kotlin.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com ferramentas de IA aplicadas ao desenvolvimento de software.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) iOS Sênior"},{"content":"Sobre a vagaA Diabolocom busca uma pessoa Engenheira de Software Backend Sênior para o Voice Squad, em modelo remoto.\nA posição aceita profissionais em Paris, Barcelona, Munique, Frankfurt am Main, Berlim, Belgrado, Limassol, Lisboa, Tbilisi, Buenos Aires, Podgorica ou Erevã.\nStack técnicoKotlin, Java e GoSpring BootPostgreSQLRabbitMQ e RedisDockerPerfilSenioridade sênior em engenharia de software Backend.Experiência com desenvolvimento de serviços Backend e sistemas distribuídos.Interesse em atuar no squad de voz, com foco em produtos e serviços de comunicação. ","permalink":"https://kotlin.dev.br/vagas/9vu0xbnsfg10gg9t-diabolocom-engenheiro-a-de-software-backend-senior-voice-squad/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Diabolocom busca uma pessoa Engenheira de Software Backend Sênior para o Voice Squad, em modelo remoto.\u003c/p\u003e\u003cp\u003eA posição aceita profissionais em Paris, Barcelona, Munique, Frankfurt am Main, Berlim, Belgrado, Limassol, Lisboa, Tbilisi, Buenos Aires, Podgorica ou Erevã.\u003c/p\u003e\u003ch3\u003eStack técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java e Go\u003c/li\u003e\u003cli\u003eSpring Boot\u003c/li\u003e\u003cli\u003ePostgreSQL\u003c/li\u003e\u003cli\u003eRabbitMQ e Redis\u003c/li\u003e\u003cli\u003eDocker\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cul\u003e\u003cli\u003eSenioridade sênior em engenharia de software Backend.\u003c/li\u003e\u003cli\u003eExperiência com desenvolvimento de serviços Backend e sistemas distribuídos.\u003c/li\u003e\u003cli\u003eInteresse em atuar no squad de voz, com foco em produtos e serviços de comunicação.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Backend Sênior, Voice Squad"},{"content":"Sobre a vagaO Banco PAN busca uma pessoa Engenheira de Software Pleno para atuar em São Paulo, em modelo híbrido, no desenvolvimento de soluções backend.\nResponsabilidadesDesenvolver e manter serviços e APIs REST usando Java, Kotlin e Spring Boot.Atuar com arquitetura hexagonal, testes unitários e boas práticas de engenharia de software.Trabalhar com bancos de dados relacionais e NoSQL, incluindo SQL, MongoDB, Redis e DynamoDB.Apoiar implantação, observabilidade e operação de aplicações em ambientes AWS com Docker e Kubernetes.Utilizar pipelines de CI/CD, Git e ferramentas de monitoramento como Kibana, Dynatrace e Grafana.RequisitosExperiência como pessoa desenvolvedora backend em nível pleno.Conhecimento em Java, Kotlin, Spring Boot e construção de APIs REST.Experiência com testes unitários e arquitetura hexagonal.Vivência com bancos de dados SQL e NoSQL.Familiaridade com AWS, Docker, Kubernetes, CI/CD e Git. ","permalink":"https://kotlin.dev.br/vagas/bm86x2l0ns86qwik-banco-pan-engenheiro-a-de-software-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO Banco PAN busca uma pessoa Engenheira de Software Pleno para atuar em São Paulo, em modelo híbrido, no desenvolvimento de soluções backend.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços e APIs REST usando Java, Kotlin e Spring Boot.\u003c/li\u003e\u003cli\u003eAtuar com arquitetura hexagonal, testes unitários e boas práticas de engenharia de software.\u003c/li\u003e\u003cli\u003eTrabalhar com bancos de dados relacionais e NoSQL, incluindo SQL, MongoDB, Redis e DynamoDB.\u003c/li\u003e\u003cli\u003eApoiar implantação, observabilidade e operação de aplicações em ambientes AWS com Docker e Kubernetes.\u003c/li\u003e\u003cli\u003eUtilizar pipelines de CI/CD, Git e ferramentas de monitoramento como Kibana, Dynatrace e Grafana.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência como pessoa desenvolvedora backend em nível pleno.\u003c/li\u003e\u003cli\u003eConhecimento em Java, Kotlin, Spring Boot e construção de APIs REST.\u003c/li\u003e\u003cli\u003eExperiência com testes unitários e arquitetura hexagonal.\u003c/li\u003e\u003cli\u003eVivência com bancos de dados SQL e NoSQL.\u003c/li\u003e\u003cli\u003eFamiliaridade com AWS, Docker, Kubernetes, CI/CD e Git.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Pleno"},{"content":"Sobre a vagaVaga presencial em São Paulo para Especialista Backend Java e Kotlin no C6 Bank, com atuação no domínio de cadastro.\nResponsabilidadesDesenvolver e manter serviços backend usando Java, Kotlin e Spring Boot.Atuar em arquitetura de microservices e integrações assíncronas.Trabalhar com mensageria, bancos de dados relacionais e NoSQL e serviços em nuvem.Contribuir com práticas de CI/CD, infraestrutura como código e segurança de APIs.RequisitosExperiência com Kotlin, Java e Spring Boot.Conhecimento em microservices, PostgreSQL e MongoDB.Experiência com Kafka, SQS, SNS e AWS.Conhecimento em Terraform, CloudFormation e pipelines de CI/CD.Familiaridade com autenticação e autorização usando JWT e OAuth2.Modelo de trabalhoPresencial em São Paulo, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/znhv8sn1ywmuhmpm-c6-bank-especialista-backend-java-e-kotlin-cadastro/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga presencial em São Paulo para Especialista Backend Java e Kotlin no C6 Bank, com atuação no domínio de cadastro.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend usando Java, Kotlin e Spring Boot.\u003c/li\u003e\u003cli\u003eAtuar em arquitetura de microservices e integrações assíncronas.\u003c/li\u003e\u003cli\u003eTrabalhar com mensageria, bancos de dados relacionais e NoSQL e serviços em nuvem.\u003c/li\u003e\u003cli\u003eContribuir com práticas de CI/CD, infraestrutura como código e segurança de APIs.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin, Java e Spring Boot.\u003c/li\u003e\u003cli\u003eConhecimento em microservices, PostgreSQL e MongoDB.\u003c/li\u003e\u003cli\u003eExperiência com Kafka, SQS, SNS e AWS.\u003c/li\u003e\u003cli\u003eConhecimento em Terraform, CloudFormation e pipelines de CI/CD.\u003c/li\u003e\u003cli\u003eFamiliaridade com autenticação e autorização usando JWT e OAuth2.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003ePresencial em São Paulo, São Paulo, Brasil.\u003c/p\u003e","title":"Especialista Backend Java e Kotlin | Cadastro"},{"content":"Sobre a vagaO C6 Bank busca uma Pessoa Desenvolvedora Android Sênior para atuar presencialmente em São Paulo na área de Corporate Banking Engineering.\nResponsabilidadesDesenvolver e manter aplicações Android usando Kotlin e Android SDK.Criar interfaces e fluxos com Jetpack Compose.Integrar aplicações mobile a APIs RESTful.Aplicar padrões como MVVM e Clean Architecture.Trabalhar com Coroutines, Flow, ViewModel, LiveData e Lifecycle.Contribuir com testes unitários, de integração e instrumentados.Participar de rotinas de versionamento com Git e pipelines de CI/CD.RequisitosExperiência sênior em desenvolvimento Android.Conhecimento sólido em Kotlin, Android SDK e arquitetura de aplicações mobile.Experiência com Jetpack Compose, Coroutines, Flow e componentes de lifecycle.Vivência com APIs RESTful, MVVM, Clean Architecture e práticas de testes.Familiaridade com Git e CI/CD. ","permalink":"https://kotlin.dev.br/vagas/i7s01s5o9duxcxrt-c6-bank-pessoa-desenvolvedora-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma Pessoa Desenvolvedora Android Sênior para atuar presencialmente em São Paulo na área de Corporate Banking Engineering.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android usando Kotlin e Android SDK.\u003c/li\u003e\u003cli\u003eCriar interfaces e fluxos com Jetpack Compose.\u003c/li\u003e\u003cli\u003eIntegrar aplicações mobile a APIs RESTful.\u003c/li\u003e\u003cli\u003eAplicar padrões como MVVM e Clean Architecture.\u003c/li\u003e\u003cli\u003eTrabalhar com Coroutines, Flow, ViewModel, LiveData e Lifecycle.\u003c/li\u003e\u003cli\u003eContribuir com testes unitários, de integração e instrumentados.\u003c/li\u003e\u003cli\u003eParticipar de rotinas de versionamento com Git e pipelines de CI/CD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin, Android SDK e arquitetura de aplicações mobile.\u003c/li\u003e\u003cli\u003eExperiência com Jetpack Compose, Coroutines, Flow e componentes de lifecycle.\u003c/li\u003e\u003cli\u003eVivência com APIs RESTful, MVVM, Clean Architecture e práticas de testes.\u003c/li\u003e\u003cli\u003eFamiliaridade com Git e CI/CD.\u003c/li\u003e\u003c/ul\u003e","title":"Pessoa Desenvolvedora Android Sênior"},{"content":"Qualidade de código em Kotlin não depende só de code review. Review humano é essencial para arquitetura, clareza de regra de negócio e decisões de produto, mas não deveria gastar energia discutindo import fora de ordem, função longa, MagicNumber, complexidade ciclomática ou formatação inconsistente. Para isso existem ferramentas automáticas.\nEm 2026, a combinação mais prática para projetos Kotlin continua sendo ktlint para estilo e formatação, detekt para análise estática e um pipeline de CI/CD que bloqueia regressões antes do merge. Esse trio funciona para Android, backend com Ktor, Spring Boot, bibliotecas JVM e projetos Kotlin Multiplatform.\nA diferença entre um setup útil e um setup irritante está na calibragem. Se o time ativa todas as regras de uma vez em um projeto legado, a ferramenta vira ruído. Se deixa tudo permissivo demais, vira decoração no build.gradle.kts. O caminho bom é começar com regras que pegam problemas reais, automatizar o que pode ser corrigido sozinho e evoluir a rigidez aos poucos.\nktlint, detekt e testes resolvem problemas diferentes Antes de configurar plugins, vale separar responsabilidades.\nktlint cuida de formatação e estilo. Ele aplica convenções próximas do estilo oficial do Kotlin: indentação, espaços, quebras de linha, imports e organização visual. É a ferramenta que evita discussões improdutivas sobre como o código “deveria parecer”.\ndetekt faz análise estática. Ele procura code smells, complexidade excessiva, nomes ruins, blocos grandes demais, exceções engolidas, duplicação conceitual e padrões que costumam dificultar manutenção. Ele não substitui testes, mas ajuda a identificar código que tende a quebrar ou ficar caro de modificar.\nTestes verificam comportamento. Um teste com JUnit 5 e MockK responde se uma regra funciona; o guia completo de testes em Kotlin ajuda a decidir onde entram coroutines, Flow, integração e Android; detekt responde se o formato do código está saudável; ktlint responde se o estilo está consistente. Quando as três camadas trabalham juntas, o review fica mais estratégico.\nConfigurando ktlint com Gradle O jeito mais comum de usar ktlint em projetos Kotlin é via plugin Gradle. Em um projeto JVM ou Android, adicione o plugin no build.gradle.kts raiz:\nplugins { id(\u0026#34;org.jlleitschuh.gradle.ktlint\u0026#34;) version \u0026#34;12.1.1\u0026#34; } ktlint { version.set(\u0026#34;1.3.1\u0026#34;) android.set(false) outputToConsole.set(true) coloredOutput.set(true) ignoreFailures.set(false) } Em projetos Android, ajuste android.set(true) para habilitar algumas convenções específicas. Depois, rode:\n./gradlew ktlintCheck ./gradlew ktlintFormat O ktlintCheck deve rodar no CI e falhar quando houver problema. O ktlintFormat pode rodar localmente antes do commit para corrigir o que é automático. Uma prática simples é documentar no README: “antes de abrir PR, rode ./gradlew ktlintFormat test”.\nPara times maiores, também vale integrar com pre-commit hook. Mas cuidado: hook local ajuda, não substitui CI. Desenvolvedor pode pular hook; pipeline não deveria pular qualidade.\nConfigurando detekt sem travar o time O detekt também entra pelo Gradle:\nplugins { id(\u0026#34;io.gitlab.arturbosch.detekt\u0026#34;) version \u0026#34;1.23.7\u0026#34; } detekt { buildUponDefaultConfig = true allRules = false config.setFrom(files(\u0026#34;config/detekt/detekt.yml\u0026#34;)) baseline = file(\u0026#34;config/detekt/baseline.xml\u0026#34;) } dependencies { detektPlugins(\u0026#34;io.gitlab.arturbosch.detekt:detekt-formatting:1.23.7\u0026#34;) } Crie a configuração inicial:\n./gradlew detektGenerateConfig mkdir -p config/detekt mv config/detekt/detekt.yml config/detekt/detekt.yml Se o projeto já tem muito código, gere um baseline:\n./gradlew detektBaseline O baseline registra problemas existentes para que o CI bloqueie apenas problemas novos. Isso é importante em sistemas reais. Em vez de tentar “arrumar tudo” em uma semana, o time impede deterioração e agenda limpezas graduais.\nRegras que valem ativar cedo Nem toda regra do detekt tem o mesmo valor. Algumas pegam problemas práticos rapidamente:\nLongMethod: funções grandes demais, difíceis de testar. LongParameterList: construtores e métodos com dependência demais. ComplexMethod: lógica condicional excessiva. TooGenericExceptionCaught: catch (Exception) escondendo falhas importantes. SwallowedException: exceção capturada e ignorada. MagicNumber: números sem nome prejudicando intenção do código. NestedBlockDepth: muitos if, when e loops aninhados. ForbiddenComment: TODO, FIXME e marcadores que não deveriam chegar em produção. Um trecho problemático que detekt apontaria:\nfun calcularTaxa(cliente: Cliente, pedido: Pedido): Double { var taxa = 0.0 if (cliente.ativo) { if (pedido.valor \u0026gt; 1000) { if (cliente.plano == \u0026#34;premium\u0026#34;) { taxa = 0.02 } else { taxa = 0.05 } } else { taxa = 0.08 } } return taxa } O código funciona, mas a intenção está enterrada em condicionais. Uma versão mais idiomática separa regras:\nfun calcularTaxa(cliente: Cliente, pedido: Pedido): Double = when { !cliente.ativo -\u0026gt; 0.0 cliente.plano == Plano.PREMIUM \u0026amp;\u0026amp; pedido.valor \u0026gt; LIMITE_PEDIDO_ALTO -\u0026gt; TAXA_PREMIUM pedido.valor \u0026gt; LIMITE_PEDIDO_ALTO -\u0026gt; TAXA_PEDIDO_ALTO else -\u0026gt; TAXA_PADRAO } private const val LIMITE_PEDIDO_ALTO = 1_000.0 private const val TAXA_PREMIUM = 0.02 private const val TAXA_PEDIDO_ALTO = 0.05 private const val TAXA_PADRAO = 0.08 Além de satisfazer regras, a segunda versão é mais fácil de revisar, testar e modificar.\nPipeline de CI para GitHub Actions Em um projeto Kotlin, o pipeline mínimo deve compilar, rodar testes, checar formatação e executar análise estática. Um exemplo com GitHub Actions:\nname: Kotlin Quality on: pull_request: push: branches: [main] jobs: quality: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: temurin java-version: 21 - uses: gradle/actions/setup-gradle@v4 - name: Check formatting run: ./gradlew ktlintCheck - name: Static analysis run: ./gradlew detekt - name: Tests run: ./gradlew test Se o projeto usa Android, substitua ou complemente com tasks como testDebugUnitTest, lintDebug e build variants relevantes. Para backend, inclua testes de integração quando fizer sentido. O guia de CI/CD para Kotlin aprofunda pipelines com GitHub Actions, GitLab CI e Jenkins.\nUma otimização útil é publicar relatórios como artefatos quando algo falha:\n- uses: actions/upload-artifact@v4 if: failure() with: name: quality-reports path: | build/reports/ **/build/reports/ Assim, quem abriu o PR consegue baixar HTML de testes, relatório do detekt e saída de lint sem reproduzir tudo localmente.\nComo aplicar em projeto legado O erro clássico em projeto legado é transformar a primeira execução em uma lista de 900 problemas. Ninguém vai corrigir isso com qualidade no meio de uma sprint. O melhor plano é incremental:\nAdicione ktlint e rode ktlintFormat em um commit isolado. Adicione detekt com baseline para problemas existentes. Bloqueie novos problemas no CI. Escolha uma regra por semana para endurecer. Remova partes do baseline conforme módulos forem refatorados. Separar commits importa. Um commit só de formatação é chato, mas fácil de revisar. Misturar formatação com mudança de regra de negócio cria diff barulhento e aumenta risco.\nPara Android, comece por módulos novos ou mais ativos. Para backend, comece por camadas de domínio e serviços com mudança frequente. O objetivo não é “zerar relatório” por vaidade; é reduzir custo de manutenção onde o time mais mexe.\nConvenções de time que evitam briga Ferramenta boa precisa de acordo social. Algumas decisões devem estar explícitas:\nQual versão de Kotlin, Gradle, detekt e ktlint o projeto usa. Se ktlintFormat pode alterar código automaticamente antes do commit. Quais regras do detekt são bloqueantes e quais são apenas aviso. Como pedir exceção para uma regra em caso específico. Quem revisa mudanças no detekt.yml. Use supressões com parcimônia:\n@Suppress(\u0026#34;LongMethod\u0026#34;) fun migracaoTemporaria() { // código transitório, com issue vinculada para remoção } A supressão deve explicar o motivo. Se o time começa a espalhar @Suppress sem justificativa, a ferramenta perdeu autoridade.\nRelação com arquitetura e performance Detekt e ktlint não decidem arquitetura. Eles não sabem se você deveria usar Ktor ou Spring Boot, se vale migrar para coroutines avançadas ou se um módulo deveria virar microsserviço. Mas eles deixam sinais objetivos: classes grandes, acoplamento alto, funções instáveis e complexidade concentrada.\nEsses sinais ajudam o time a priorizar refatorações. Se uma classe aparece em todo relatório, muda toda semana e concentra bugs, ela é candidata a extração, testes melhores ou redesenho. Em backends de alta concorrência, o mesmo raciocínio vale para serviços assíncronos com Flow e mensageria com Kafka e RabbitMQ.\nTambém existe aprendizado fora do ecossistema Kotlin. Times que trabalham com Go costumam automatizar gofmt, go vet e testes desde cedo; vale comparar essa disciplina com os guias de Go para backend no Brasil. A tecnologia muda, mas a ideia é a mesma: tirar decisões repetitivas do review humano.\nChecklist recomendado para 2026 Para um projeto Kotlin novo, eu começaria assim:\nKotlin e JDK atualizados conforme suporte do projeto. Gradle com Kotlin DSL. ktlint rodando localmente e no CI. detekt com configuração versionada em config/detekt/detekt.yml. Testes unitários obrigatórios em PR. Relatórios publicados como artefatos quando o pipeline falhar. Baseline apenas se o projeto já for legado. Revisão mensal das regras que geram mais ruído. Para um projeto existente, não tente virar “perfeito” em uma sexta-feira. Automatize primeiro, bloqueie regressão depois e só então endureça o padrão. Qualidade sustentável é mais parecida com higiene diária do que com mutirão heroico.\nConclusão Detekt e ktlint são ferramentas pequenas perto das decisões de produto, mas mudam a rotina de um time Kotlin. Elas reduzem ruído no review, tornam padrões explícitos, ajudam pessoas novas a entender o estilo do projeto e criam uma base confiável para evoluir código sem medo.\nO segredo é usar automação como apoio, não como burocracia. ktlint deve corrigir o que é mecânico. detekt deve apontar riscos reais. O CI deve proteger a branch principal. E o time deve reservar energia humana para o que ferramenta nenhuma entende bem: clareza de domínio, experiência do usuário, trade-offs de arquitetura e entrega de valor.\n","permalink":"https://kotlin.dev.br/blog/detekt-ktlint-kotlin-qualidade-2026/","summary":"\u003cp\u003eQualidade de código em Kotlin não depende só de code review. Review humano é essencial para arquitetura, clareza de regra de negócio e decisões de produto, mas não deveria gastar energia discutindo import fora de ordem, função longa, \u003ccode\u003eMagicNumber\u003c/code\u003e, complexidade ciclomática ou formatação inconsistente. Para isso existem ferramentas automáticas.\u003c/p\u003e\n\u003cp\u003eEm 2026, a combinação mais prática para projetos Kotlin continua sendo \u003cstrong\u003ektlint\u003c/strong\u003e para estilo e formatação, \u003cstrong\u003edetekt\u003c/strong\u003e para análise estática e um pipeline de \u003cstrong\u003eCI/CD\u003c/strong\u003e que bloqueia regressões antes do merge. Esse trio funciona para Android, backend com \u003ca href=\"/blog/ktor-criando-apis-kotlin/\"\u003eKtor\u003c/a\u003e, \u003ca href=\"/blog/kotlin-spring-boot/\"\u003eSpring Boot\u003c/a\u003e, bibliotecas JVM e projetos \u003ca href=\"/blog/kotlin-multiplatform/\"\u003eKotlin Multiplatform\u003c/a\u003e.\u003c/p\u003e","title":"Detekt e ktlint em Kotlin: Qualidade de Código em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA BV busca uma pessoa Analista de Desenvolvimento de Sistemas Java Sênior para atuação remota no Brasil.\nResponsabilidadesDesenvolver e manter sistemas e integrações usando Java e tecnologias relacionadas.Trabalhar com APIs REST, mensageria e soluções em nuvem.Aplicar práticas de CI/CD, TDD e DDD no ciclo de desenvolvimento.RequisitosExperiência sênior em desenvolvimento de sistemas com Java.Conhecimento em Kotlin, Go ou Python.Experiência com GCP, Kafka e Pub/Sub.Vivência com APIs REST, CI/CD, TDD e DDD.Tecnologias mencionadasJava, Kotlin, Go e Python.GCP, Kafka, Pub/Sub e APIs REST.Streamlit e Gradio. ","permalink":"https://kotlin.dev.br/vagas/l9jmqs6g3xjxo8ci-bv-analista-de-desenvolvimento-de-sistemas-java-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA BV busca uma pessoa \u003cstrong\u003eAnalista de Desenvolvimento de Sistemas Java Sênior\u003c/strong\u003e para atuação remota no Brasil.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter sistemas e integrações usando Java e tecnologias relacionadas.\u003c/li\u003e\u003cli\u003eTrabalhar com APIs REST, mensageria e soluções em nuvem.\u003c/li\u003e\u003cli\u003eAplicar práticas de CI/CD, TDD e DDD no ciclo de desenvolvimento.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento de sistemas com Java.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Go ou Python.\u003c/li\u003e\u003cli\u003eExperiência com GCP, Kafka e Pub/Sub.\u003c/li\u003e\u003cli\u003eVivência com APIs REST, CI/CD, TDD e DDD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eJava, Kotlin, Go e Python.\u003c/li\u003e\u003cli\u003eGCP, Kafka, Pub/Sub e APIs REST.\u003c/li\u003e\u003cli\u003eStreamlit e Gradio.\u003c/li\u003e\u003c/ul\u003e","title":"Analista de Desenvolvimento de Sistemas Java Sênior"},{"content":"Sobre a vagaA Encora busca uma pessoa Engenheira Android Sênior para atuação remota a partir da Bolívia.\nRequisitosExperiência sênior em desenvolvimento Android.Conhecimento em Kotlin e Kotlin Coroutines.Experiência com Jetpack Compose.Conhecimento em GraphQL.Vivência com Clean Architecture.Modelo de trabalhoVaga remota.\n","permalink":"https://kotlin.dev.br/vagas/kt40tasd6xh834zs-encora-engenheiro-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Encora busca uma pessoa Engenheira Android Sênior para atuação remota a partir da Bolívia.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eKotlin Coroutines\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eJetpack Compose\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eGraphQL\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com \u003cstrong\u003eClean Architecture\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota.\u003c/p\u003e","title":"Engenheiro Android Sênior"},{"content":"Sobre a vagaA Encora busca uma pessoa Engenheira Android Sênior para atuação remota na Colômbia.\nStack e atuaçãoDesenvolvimento Android com Kotlin.Uso de Kotlin Coroutines para programação assíncrona.Construção de interfaces com Jetpack Compose.Integração com APIs GraphQL.Aplicação de princípios de Clean Architecture.SenioridadeVaga de nível sênior.\n","permalink":"https://kotlin.dev.br/vagas/x84wfgncrmfazw27-encora-engenheiro-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Encora busca uma pessoa Engenheira Android Sênior para atuação remota na Colômbia.\u003c/p\u003e\u003ch3\u003eStack e atuação\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolvimento Android com \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eKotlin Coroutines\u003c/strong\u003e para programação assíncrona.\u003c/li\u003e\u003cli\u003eConstrução de interfaces com \u003cstrong\u003eJetpack Compose\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eIntegração com APIs \u003cstrong\u003eGraphQL\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eAplicação de princípios de \u003cstrong\u003eClean Architecture\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade\u003c/h3\u003e\u003cp\u003eVaga de nível sênior.\u003c/p\u003e","title":"Engenheiro Android Sênior"},{"content":"Sobre a vagaA Encora busca uma pessoa Engenheira Android Sênior para atuação remota no Peru, com foco em desenvolvimento Android moderno.\nRequisitosExperiência sênior em desenvolvimento Android.Conhecimento sólido em Kotlin e Kotlin Coroutines.Experiência com Jetpack Compose.Conhecimento em Clean Architecture.Experiência com integração via GraphQL. ","permalink":"https://kotlin.dev.br/vagas/xcxdqic8q5lo6jr9-encora-engenheiro-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Encora busca uma pessoa Engenheira Android Sênior para atuação remota no Peru, com foco em desenvolvimento Android moderno.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento sólido em \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eKotlin Coroutines\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eJetpack Compose\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eClean Architecture\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com integração via \u003cstrong\u003eGraphQL\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro Android Sênior"},{"content":"Sobre a vagaA Platform Science busca uma pessoa Engenheira de Software Pleno para atuação híbrida em Londrina, Paraná.\nTecnologias mencionadasKotlin, Java e Node.jsReact e AngularPostgreSQL, MySQL, MongoDB e RedisAWS, Azure, GCP e TerraformKafka, RabbitMQ, ElasticSearch, Serverless e AndroidModelo de trabalhoVaga híbrida em Londrina, Paraná, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/iq19ao3skx7ayvhl-platform-science-engenheiro-de-software-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Platform Science busca uma pessoa Engenheira de Software Pleno para atuação híbrida em Londrina, Paraná.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java e Node.js\u003c/li\u003e\u003cli\u003eReact e Angular\u003c/li\u003e\u003cli\u003ePostgreSQL, MySQL, MongoDB e Redis\u003c/li\u003e\u003cli\u003eAWS, Azure, GCP e Terraform\u003c/li\u003e\u003cli\u003eKafka, RabbitMQ, ElasticSearch, Serverless e Android\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga híbrida em Londrina, Paraná, Brasil.\u003c/p\u003e","title":"Engenheiro de Software Pleno"},{"content":"Sobre a vagaO Banco PAN busca uma pessoa Engenheira de Software Sênior para atuar em São Paulo, em modelo híbrido, no desenvolvimento de soluções backend com Java, Kotlin e Spring Boot.\nResponsabilidadesDesenvolver e manter APIs REST, BFFs e microsserviços.Aplicar arquitetura hexagonal, design orientado a objetos e boas práticas de engenharia de software.Construir soluções com foco em qualidade, testes automatizados, observabilidade e entrega contínua.Trabalhar em times ágeis usando práticas como Scrum, Kanban ou XP.Colaborar com pipelines de CI/CD, versionamento e revisão de código.RequisitosExperiência sênior com Java, Kotlin e Spring Boot.Conhecimento em APIs REST, microsserviços, BFF e arquitetura hexagonal.Experiência com testes automatizados, estruturas de dados e algoritmos.Vivência com bancos de dados SQL e NoSQL, incluindo MongoDB, Redis ou DynamoDB.Experiência com AWS, Docker e Kubernetes.Conhecimento em CI/CD com GitHub Actions, Jenkins ou Azure DevOps.Uso de Git, GitFlow e ferramentas de qualidade como SonarQube.Conhecimento em monitoramento e observabilidade com Kibana, Dynatrace ou Grafana. ","permalink":"https://kotlin.dev.br/vagas/c342lkgjpmb2gils-banco-pan-engenheiro-a-de-software-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO Banco PAN busca uma pessoa Engenheira de Software Sênior para atuar em São Paulo, em modelo híbrido, no desenvolvimento de soluções backend com Java, Kotlin e Spring Boot.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter APIs REST, BFFs e microsserviços.\u003c/li\u003e\u003cli\u003eAplicar arquitetura hexagonal, design orientado a objetos e boas práticas de engenharia de software.\u003c/li\u003e\u003cli\u003eConstruir soluções com foco em qualidade, testes automatizados, observabilidade e entrega contínua.\u003c/li\u003e\u003cli\u003eTrabalhar em times ágeis usando práticas como Scrum, Kanban ou XP.\u003c/li\u003e\u003cli\u003eColaborar com pipelines de CI/CD, versionamento e revisão de código.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com Java, Kotlin e Spring Boot.\u003c/li\u003e\u003cli\u003eConhecimento em APIs REST, microsserviços, BFF e arquitetura hexagonal.\u003c/li\u003e\u003cli\u003eExperiência com testes automatizados, estruturas de dados e algoritmos.\u003c/li\u003e\u003cli\u003eVivência com bancos de dados SQL e NoSQL, incluindo MongoDB, Redis ou DynamoDB.\u003c/li\u003e\u003cli\u003eExperiência com AWS, Docker e Kubernetes.\u003c/li\u003e\u003cli\u003eConhecimento em CI/CD com GitHub Actions, Jenkins ou Azure DevOps.\u003c/li\u003e\u003cli\u003eUso de Git, GitFlow e ferramentas de qualidade como SonarQube.\u003c/li\u003e\u003cli\u003eConhecimento em monitoramento e observabilidade com Kibana, Dynatrace ou Grafana.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Sênior"},{"content":"Sobre a vagaO iFood busca uma pessoa Gerente Técnico de Contas de nível pleno para atuação presencial em Osasco, São Paulo.\nInformações principaisEmpresa: iFoodLocal: Osasco, São Paulo, BrasilModelo de trabalho: PresencialNível: PlenoTecnologias relacionadasAWSDockerInfrastructure as CodeSQLNoSQL ","permalink":"https://kotlin.dev.br/vagas/b3651yd7gelgctqx-ifood-gerente-tecnico-de-contas/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa Gerente Técnico de Contas de nível pleno para atuação presencial em Osasco, São Paulo.\u003c/p\u003e\u003ch3\u003eInformações principais\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eEmpresa:\u003c/strong\u003e iFood\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eLocal:\u003c/strong\u003e Osasco, São Paulo, Brasil\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eModelo de trabalho:\u003c/strong\u003e Presencial\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eNível:\u003c/strong\u003e Pleno\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias relacionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eDocker\u003c/li\u003e\u003cli\u003eInfrastructure as Code\u003c/li\u003e\u003cli\u003eSQL\u003c/li\u003e\u003cli\u003eNoSQL\u003c/li\u003e\u003c/ul\u003e","title":"Gerente Técnico de Contas"},{"content":"Sobre a vagaVaga presencial de nível pleno para Gerente Técnico de Contas no iFood, em Osasco, São Paulo. A posição envolve suporte técnico a contas, análise de integrações e comunicação entre áreas técnicas e stakeholders.\nResponsabilidadesAtuar como ponto de contato técnico para contas e integrações.Investigar problemas em APIs, bancos de dados, filas de mensagens e ambientes de aplicação.Apoiar diagnósticos envolvendo serviços em AWS, Docker e infraestrutura como código.Interagir com times de engenharia para acompanhamento e resolução de incidentes técnicos.Documentar análises, recomendações e próximos passos técnicos.RequisitosExperiência em suporte técnico, engenharia de soluções, integrações ou gestão técnica de contas.Conhecimento em Kotlin ou Java.Experiência com APIs, SQL, NoSQL e filas de mensagens.Familiaridade com AWS, Docker e IaC.Boa comunicação para traduzir temas técnicos para diferentes públicos.Informações da vagaSenioridade: pleno.Modelo de trabalho: presencial.Local: Osasco, São Paulo, Brasil. ","permalink":"https://kotlin.dev.br/vagas/q6wrrsx5rmzj232d-ifood-gerente-tecnico-de-contas/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga presencial de nível pleno para \u003cstrong\u003eGerente Técnico de Contas\u003c/strong\u003e no iFood, em Osasco, São Paulo. A posição envolve suporte técnico a contas, análise de integrações e comunicação entre áreas técnicas e stakeholders.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAtuar como ponto de contato técnico para contas e integrações.\u003c/li\u003e\u003cli\u003eInvestigar problemas em APIs, bancos de dados, filas de mensagens e ambientes de aplicação.\u003c/li\u003e\u003cli\u003eApoiar diagnósticos envolvendo serviços em AWS, Docker e infraestrutura como código.\u003c/li\u003e\u003cli\u003eInteragir com times de engenharia para acompanhamento e resolução de incidentes técnicos.\u003c/li\u003e\u003cli\u003eDocumentar análises, recomendações e próximos passos técnicos.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em suporte técnico, engenharia de soluções, integrações ou gestão técnica de contas.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e ou Java.\u003c/li\u003e\u003cli\u003eExperiência com APIs, SQL, NoSQL e filas de mensagens.\u003c/li\u003e\u003cli\u003eFamiliaridade com AWS, Docker e IaC.\u003c/li\u003e\u003cli\u003eBoa comunicação para traduzir temas técnicos para diferentes públicos.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eInformações da vaga\u003c/h3\u003e\u003cul\u003e\u003cli\u003eSenioridade: pleno.\u003c/li\u003e\u003cli\u003eModelo de trabalho: presencial.\u003c/li\u003e\u003cli\u003eLocal: Osasco, São Paulo, Brasil.\u003c/li\u003e\u003c/ul\u003e","title":"Gerente Técnico de Contas"},{"content":"Sobre a vagaO C6 Bank busca uma Pessoa Desenvolvedora Android Sênior para atuar no time de App Platform, com foco em desenvolvimento mobile Android.\nRequisitos e tecnologiasExperiência sênior com desenvolvimento Android.Conhecimento em Kotlin, Android SDK e Jetpack Compose.Experiência com REST API, Coroutines e controle de versão com Git.Vivência com CI/CD, arquitetura MVVM e Clean Architecture.Prática com testes unitários e otimização de performance de UI.Local de trabalhoVaga presencial em São Paulo, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/by6b9d7kertb9rix-c6-bank-pessoa-desenvolvedora-android-senior-app-platform/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma Pessoa Desenvolvedora Android Sênior para atuar no time de App Platform, com foco em desenvolvimento mobile Android.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e, \u003cstrong\u003eAndroid SDK\u003c/strong\u003e e \u003cstrong\u003eJetpack Compose\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eREST API\u003c/strong\u003e, \u003cstrong\u003eCoroutines\u003c/strong\u003e e controle de versão com \u003cstrong\u003eGit\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com \u003cstrong\u003eCI/CD\u003c/strong\u003e, arquitetura \u003cstrong\u003eMVVM\u003c/strong\u003e e \u003cstrong\u003eClean Architecture\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003ePrática com testes unitários e otimização de performance de UI.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em São Paulo, São Paulo, Brasil.\u003c/p\u003e","title":"Pessoa Desenvolvedora Android Sênior | App Platform"},{"content":"Sobre a vagaO C6 Bank busca uma Pessoa Desenvolvedora Backend Sênior Kotlin/Java para atuar presencialmente em São Paulo na área de Átomos e Marketplace.\nResponsabilidadesDesenvolver e manter serviços backend com Kotlin, Java e Spring Boot.Trabalhar com arquitetura de microsserviços e sistemas orientados a eventos.Integrar aplicações com Kafka, SQS, SNS e serviços AWS.Apoiar práticas de CI/CD, observabilidade, segurança e infraestrutura como código.Atuar com bancos de dados relacionais e NoSQL, como PostgreSQL, MongoDB e Cassandra.RequisitosExperiência sênior em desenvolvimento backend.Conhecimento em Kotlin, Java e Spring Boot.Experiência com microsserviços, mensageria e arquitetura event driven.Vivência com AWS, CI/CD, observabilidade e boas práticas de segurança.Experiência com PostgreSQL, MongoDB ou Cassandra.Modelo de trabalhoVaga presencial em São Paulo, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/p2n3a9ujpnx1a331-c6-bank-pessoa-desenvolvedora-backend-senior-kotlin-java/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma Pessoa Desenvolvedora Backend Sênior Kotlin/Java para atuar presencialmente em São Paulo na área de Átomos e Marketplace.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend com Kotlin, Java e Spring Boot.\u003c/li\u003e\u003cli\u003eTrabalhar com arquitetura de microsserviços e sistemas orientados a eventos.\u003c/li\u003e\u003cli\u003eIntegrar aplicações com Kafka, SQS, SNS e serviços AWS.\u003c/li\u003e\u003cli\u003eApoiar práticas de CI/CD, observabilidade, segurança e infraestrutura como código.\u003c/li\u003e\u003cli\u003eAtuar com bancos de dados relacionais e NoSQL, como PostgreSQL, MongoDB e Cassandra.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento backend.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Java e Spring Boot.\u003c/li\u003e\u003cli\u003eExperiência com microsserviços, mensageria e arquitetura event driven.\u003c/li\u003e\u003cli\u003eVivência com AWS, CI/CD, observabilidade e boas práticas de segurança.\u003c/li\u003e\u003cli\u003eExperiência com PostgreSQL, MongoDB ou Cassandra.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em São Paulo, São Paulo, Brasil.\u003c/p\u003e","title":"Pessoa Desenvolvedora Backend Sênior Kotlin/Java"},{"content":"Mensageria é uma das habilidades que separam um backend Kotlin simples de um backend pronto para produção. Em sistemas pequenos, uma API REST com banco de dados resolve muita coisa. Mas conforme o produto cresce, surgem operações que não precisam acontecer no mesmo request: envio de e-mail, atualização de estoque, geração de nota, conciliação de pagamento, processamento de imagem, integração com parceiros e publicação de eventos para analytics.\nÉ nesse ponto que entram Kafka, RabbitMQ, SQS e outros brokers. Para quem trabalha com Kotlin, o tema é especialmente interessante porque a linguagem combina bem com processamento assíncrono, coroutines, Flow e frameworks backend como Spring Boot e Ktor. Este guia mostra como pensar mensageria em Kotlin em 2026, sem transformar toda aplicação em uma arquitetura distribuída difícil de operar.\nO que é mensageria no backend? Mensageria é a comunicação entre partes do sistema por meio de mensagens enviadas a um broker. Em vez de um serviço chamar outro diretamente e esperar a resposta, ele publica uma mensagem dizendo que algo aconteceu ou pedindo que uma tarefa seja executada.\nUm exemplo comum em e-commerce:\nA API recebe um pedido. O pedido é salvo no banco. A aplicação publica o evento PedidoCriado. Um consumidor envia e-mail de confirmação. Outro consumidor atualiza estoque. Outro consumidor gera dados para recomendação. O request principal não precisa esperar tudo isso terminar. O usuário recebe uma resposta rápida, e o restante do trabalho acontece em background.\nEsse modelo é útil para reduzir acoplamento, absorver picos de tráfego e aumentar resiliência. Também exige disciplina: mensagens podem duplicar, chegar fora de ordem, falhar temporariamente ou ser reprocessadas depois de minutos.\nKafka, RabbitMQ ou fila simples? A primeira decisão técnica é entender o tipo de problema. Nem todo uso de mensageria precisa de Kafka.\nRabbitMQ costuma funcionar muito bem para filas de trabalho, roteamento flexível e processamento assíncrono clássico. Se você tem tarefas que precisam ser consumidas por workers, com confirmação de processamento e retentativas, RabbitMQ é uma escolha direta.\nKafka brilha quando o sistema precisa de stream de eventos, alto volume, retenção por tempo, replay e múltiplos consumidores independentes. Ele é comum em plataformas de dados, antifraude, observabilidade, integrações de larga escala e arquiteturas event-driven.\nSQS, Pub/Sub e serviços gerenciados são ótimas opções quando o time quer reduzir operação. Em muitos produtos brasileiros rodando na AWS, SQS é suficiente para filas assíncronas, enquanto Kafka fica reservado para cenários em que retenção, replay e throughput realmente importam.\nUma regra prática:\nUse fila simples para tarefas assíncronas. Use RabbitMQ quando você precisa de roteamento, acknowledgements e workers previsíveis. Use Kafka quando eventos são parte do produto e precisam ser reprocessados por vários consumidores. Kotlin combina com consumidores assíncronos Kotlin ajuda porque permite escrever consumidores de forma expressiva sem abandonar a JVM. Você pode usar bibliotecas Java maduras e ainda modelar mensagens com data class, validação explícita e serialização type-safe.\nUm evento simples pode ser representado assim:\nimport kotlinx.serialization.Serializable @Serializable data class PedidoCriadoEvent( val pedidoId: String, val clienteId: String, val valorTotal: Long, val criadoEm: String, val versao: Int = 1 ) O campo versao parece detalhe, mas evita dor quando o contrato evolui. Em mensageria, produtores e consumidores nem sempre são implantados ao mesmo tempo. Mensagens antigas podem continuar no broker enquanto o código novo já está em produção.\nExemplo com Spring Boot e Kafka Spring Boot segue sendo uma das escolhas mais fortes para backend Kotlin enterprise. Com Spring Kafka, um consumidor fica enxuto:\n@Service class PedidoCriadoConsumer( private val notaFiscalService: NotaFiscalService, private val objectMapper: ObjectMapper ) { private val logger = LoggerFactory.getLogger(javaClass) @KafkaListener(topics = [\u0026#34;pedido-criado\u0026#34;], groupId = \u0026#34;notas-fiscais\u0026#34;) fun consumir(payload: String) { val evento = objectMapper.readValue(payload, PedidoCriadoEvent::class.java) logger.info(\u0026#34;Processando pedido criado: pedidoId={}\u0026#34;, evento.pedidoId) notaFiscalService.emitirNota( pedidoId = evento.pedidoId, clienteId = evento.clienteId, valorTotal = evento.valorTotal ) } } O exemplo é propositalmente simples. Em produção, você adicionaria validação, tratamento de erro, métricas, tracing e idempotência. O ponto é que Kotlin não exige um modelo especial: ele aproveita o ecossistema Java, mas deixa o código mais compacto.\nSe você já usa monólito modular com Kotlin e Spring, eventos internos podem ser um passo intermediário antes de introduzir Kafka. Primeiro modele eventos dentro do processo; depois promova para mensageria externa quando existir necessidade operacional real.\nExemplo com RabbitMQ e workers Kotlin RabbitMQ é muito usado para filas de trabalho. Imagine uma aplicação que precisa processar imagens enviadas por usuários. A API publica uma mensagem e workers consomem.\nUm worker Kotlin pode seguir esta ideia:\nclass ProcessarImagemWorker( private val canal: Channel, private val processador: ProcessadorImagem, private val json: Json ) { fun iniciar() { canal.basicConsume(\u0026#34;imagens.processar\u0026#34;, false) { _, delivery -\u0026gt; val mensagem = json.decodeFromString\u0026lt;ImagemRecebidaEvent\u0026gt;( delivery.body.decodeToString() ) try { processador.processar(mensagem.imagemId) canal.basicAck(delivery.envelope.deliveryTag, false) } catch (erro: Exception) { canal.basicNack(delivery.envelope.deliveryTag, false, true) } } } } O detalhe importante é o basicAck. A mensagem só é removida da fila quando o processamento termina com sucesso. Se o worker cair no meio, RabbitMQ pode entregar a mensagem novamente.\nPor isso, qualquer consumidor precisa ser idempotente: processar a mesma mensagem duas vezes não pode quebrar o sistema. Você pode garantir isso salvando uma chave única de processamento, usando constraints no banco ou checando o status antes de executar uma ação externa.\nOnde entram coroutines? Coroutines são úteis em consumidores que fazem I/O: chamadas HTTP, banco de dados, storage, APIs externas e serviços internos. Elas permitem concorrência com código legível, especialmente quando combinadas com coroutineScope, supervisorScope e limites claros de paralelismo.\nMas cuidado: não use coroutines para esconder ausência de backpressure. Se um consumidor puxa 10 mil mensagens e dispara 10 mil coroutines sem limite, você só move o gargalo para outro lugar.\nPrefira um modelo com paralelismo controlado:\nval dispatcher = Dispatchers.IO.limitedParallelism(16) suspend fun processarLote(mensagens: List\u0026lt;Mensagem\u0026gt;) = coroutineScope { mensagens.map { mensagem -\u0026gt; async(dispatcher) { processarMensagem(mensagem) } }.awaitAll() } Esse limite precisa refletir banco, APIs externas e CPU disponível. O número certo não vem da linguagem; vem de medição.\nBoas práticas para produção Mensageria em Kotlin exige mais arquitetura do que sintaxe. Antes de publicar o primeiro evento, defina alguns contratos:\nNome do evento: prefira passado, como PedidoCriado, PagamentoAprovado ou ClienteAtualizado. Schema versionado: inclua versao ou use um schema registry quando o volume justificar. Idempotência: consumidores precisam tolerar mensagens duplicadas. Dead letter queue: mensagens que falham repetidamente devem ir para uma fila de análise, não travar o fluxo principal. Observabilidade: registre messageId, correlationId, nome do tópico/fila e tempo de processamento. Retentativas com cuidado: retry infinito pode derrubar dependências externas e aumentar o incidente. Também vale separar evento de domínio de comando técnico. PedidoCriado descreve algo que aconteceu. EnviarEmailConfirmacao é uma instrução para um worker. Os dois modelos são válidos, mas misturá-los sem clareza gera acoplamento confuso.\nComo isso aparece em vagas Kotlin Mensageria aparece com frequência em vagas backend Kotlin porque empresas brasileiras usam a linguagem em sistemas de pagamento, varejo, fintech, logística, delivery e plataformas internas. Em muitos anúncios, os requisitos vêm como “Kafka”, “RabbitMQ”, “SQS”, “arquitetura orientada a eventos” ou “microsserviços”.\nPara carreira, isso significa que estudar mensageria tem retorno claro. Um desenvolvedor que já domina Kotlin para backend, testes com Kotlin, Redis para cache e rate limiting e observabilidade sobe de nível quando consegue explicar trade-offs entre REST síncrono, cache compartilhado, fila assíncrona e event streaming.\nSe você também acompanha outras linguagens backend, vale comparar com Go, que é muito usado em consumidores leves e serviços de infraestrutura. Kotlin, por outro lado, costuma vencer quando o time já está no ecossistema JVM e quer produtividade com type safety forte.\nRoteiro prático de estudo Para aprender sem se perder, siga uma ordem simples:\nCrie uma API Kotlin que publica mensagens após salvar uma entidade. Implemente um worker que consome a fila e atualiza outra tabela. Adicione retry, dead letter queue e logs estruturados. Simule duplicidade e garanta idempotência. Meça throughput, latência e consumo de memória. Só depois teste Kafka, particionamento, consumer groups e replay. Esse caminho é mais útil do que começar por uma arquitetura enorme. O valor está em entender o comportamento operacional: o que acontece quando o broker cai, quando o consumidor falha, quando uma mensagem é inválida ou quando um deploy muda o schema.\nConclusão Kotlin é uma excelente escolha para sistemas com mensageria porque combina expressividade, JVM, bibliotecas maduras e concorrência moderna. Kafka, RabbitMQ e filas gerenciadas resolvem problemas diferentes; a melhor decisão depende do volume, do nível de acoplamento desejado, da necessidade de replay e da capacidade operacional do time.\nPara a maioria dos projetos, o melhor começo é pequeno: uma fila para tarefas assíncronas, contratos bem definidos, idempotência desde o primeiro dia e observabilidade suficiente para depurar falhas. Depois, quando eventos virarem parte central do produto, Kafka e event streaming entram com muito mais clareza.\nQuem domina esse conjunto deixa de ser apenas “dev Kotlin” e passa a atuar como desenvolvedor backend capaz de desenhar sistemas que aguentam produção.\n","permalink":"https://kotlin.dev.br/blog/kotlin-kafka-rabbitmq-mensageria-2026/","summary":"\u003cp\u003eMensageria é uma das habilidades que separam um backend Kotlin simples de um backend pronto para produção. Em sistemas pequenos, uma API REST com banco de dados resolve muita coisa. Mas conforme o produto cresce, surgem operações que não precisam acontecer no mesmo request: envio de e-mail, atualização de estoque, geração de nota, conciliação de pagamento, processamento de imagem, integração com parceiros e publicação de eventos para analytics.\u003c/p\u003e\n\u003cp\u003eÉ nesse ponto que entram \u003cstrong\u003eKafka\u003c/strong\u003e, \u003cstrong\u003eRabbitMQ\u003c/strong\u003e, \u003cstrong\u003eSQS\u003c/strong\u003e e outros brokers. Para quem trabalha com Kotlin, o tema é especialmente interessante porque a linguagem combina bem com processamento assíncrono, \u003ca href=\"/blog/coroutines-kotlin/\"\u003ecoroutines\u003c/a\u003e, \u003ca href=\"/blog/kotlin-flow/\"\u003eFlow\u003c/a\u003e e frameworks backend como \u003ca href=\"/blog/kotlin-spring-boot/\"\u003eSpring Boot\u003c/a\u003e e \u003ca href=\"/blog/ktor-criando-apis-kotlin/\"\u003eKtor\u003c/a\u003e. Este guia mostra como pensar mensageria em Kotlin em 2026, sem transformar toda aplicação em uma arquitetura distribuída difícil de operar.\u003c/p\u003e","title":"Kotlin com Kafka e RabbitMQ: Mensageria em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA Jalasoft busca uma pessoa Desenvolvedora Android Sênior para atuação remota na Colômbia, com foco em desenvolvimento mobile Android.\nRequisitosExperiência sênior em desenvolvimento Android.Conhecimento em Kotlin e Java.Experiência com Android SDK, Gradle e Jetpack.Uso de Git em fluxos de desenvolvimento colaborativo.Experiência com CI/CD e frameworks de testes.Modelo de trabalhoVaga remota para profissionais localizados na Colômbia.\n","permalink":"https://kotlin.dev.br/vagas/2ncs4alpalzud7se-jalasoft-desenvolvedor-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Jalasoft busca uma pessoa Desenvolvedora Android Sênior para atuação remota na Colômbia, com foco em desenvolvimento mobile Android.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eJava\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eAndroid SDK\u003c/strong\u003e, \u003cstrong\u003eGradle\u003c/strong\u003e e \u003cstrong\u003eJetpack\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eGit\u003c/strong\u003e em fluxos de desenvolvimento colaborativo.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eCI/CD\u003c/strong\u003e e frameworks de testes.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais localizados na Colômbia.\u003c/p\u003e","title":"Desenvolvedor Android Sênior"},{"content":"Sobre a vagaA Jalasoft busca uma pessoa Desenvolvedora Android Sênior para atuar remotamente a partir da Argentina.\nStack e tecnologiasKotlin e JavaAndroid SDK, Gradle e JetpackTestes unitários e testes de integraçãoGitPerfilSenioridade: sêniorExperiência sólida em desenvolvimento AndroidConhecimento em práticas de testes e controle de versão ","permalink":"https://kotlin.dev.br/vagas/ctb8yqfipyol8i9q-jalasoft-desenvolvedor-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Jalasoft busca uma pessoa \u003cstrong\u003eDesenvolvedora Android Sênior\u003c/strong\u003e para atuar remotamente a partir da Argentina.\u003c/p\u003e\u003ch3\u003eStack e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Java\u003c/li\u003e\u003cli\u003eAndroid SDK, Gradle e Jetpack\u003c/li\u003e\u003cli\u003eTestes unitários e testes de integração\u003c/li\u003e\u003cli\u003eGit\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cul\u003e\u003cli\u003eSenioridade: sênior\u003c/li\u003e\u003cli\u003eExperiência sólida em desenvolvimento Android\u003c/li\u003e\u003cli\u003eConhecimento em práticas de testes e controle de versão\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android Sênior"},{"content":"Sobre a vagaA Jalasoft busca uma pessoa Desenvolvedora Android Sênior para atuação remota no Peru.\nA vaga envolve desenvolvimento Android com Kotlin e Java, usando Android SDK, Gradle, Jetpack, Git, CI/CD e frameworks de teste.\nRequisitosExperiência sênior em desenvolvimento Android.Conhecimento em Kotlin e Java.Experiência com Android SDK, Gradle e Jetpack.Uso de Git no fluxo de desenvolvimento.Vivência com pipelines de CI/CD.Experiência com frameworks de teste para aplicações Android.Formato de trabalhoRemoto.Localização: Peru. ","permalink":"https://kotlin.dev.br/vagas/zdh559j1bnjmidfd-jalasoft-desenvolvedor-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Jalasoft busca uma pessoa Desenvolvedora Android Sênior para atuação remota no Peru.\u003c/p\u003e\u003cp\u003eA vaga envolve desenvolvimento Android com \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eJava\u003c/strong\u003e, usando Android SDK, Gradle, Jetpack, Git, CI/CD e frameworks de teste.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin e Java.\u003c/li\u003e\u003cli\u003eExperiência com Android SDK, Gradle e Jetpack.\u003c/li\u003e\u003cli\u003eUso de Git no fluxo de desenvolvimento.\u003c/li\u003e\u003cli\u003eVivência com pipelines de CI/CD.\u003c/li\u003e\u003cli\u003eExperiência com frameworks de teste para aplicações Android.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFormato de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eRemoto.\u003c/li\u003e\u003cli\u003eLocalização: Peru.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android Sênior"},{"content":"Sobre a vagaA Jalasoft busca uma pessoa Desenvolvedora Android Sênior para atuação remota no Brasil, com foco em desenvolvimento mobile usando Kotlin, Java e Android SDK.\nRequisitosExperiência sênior em desenvolvimento Android.Conhecimento em Kotlin e Java.Experiência com Android SDK, Gradle e Jetpack.Prática com testes unitários e testes de integração.Uso de Git no fluxo de desenvolvimento.Modelo de trabalhoRemoto, com atuação a partir do Brasil.Nível de senioridade: Sênior. ","permalink":"https://kotlin.dev.br/vagas/y8xw08jvub24qzxp-jalasoft-desenvolvedor-a-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Jalasoft busca uma pessoa Desenvolvedora Android Sênior para atuação remota no Brasil, com foco em desenvolvimento mobile usando Kotlin, Java e Android SDK.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin e Java.\u003c/li\u003e\u003cli\u003eExperiência com Android SDK, Gradle e Jetpack.\u003c/li\u003e\u003cli\u003ePrática com testes unitários e testes de integração.\u003c/li\u003e\u003cli\u003eUso de Git no fluxo de desenvolvimento.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eRemoto, com atuação a partir do Brasil.\u003c/li\u003e\u003cli\u003eNível de senioridade: Sênior.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Android Sênior"},{"content":"Sobre a vagaA TEAM International tem uma vaga plena remota para atuação com stack full stack, incluindo Kotlin, Java, TypeScript, React, Spring Boot, PostgreSQL e AWS.\nStack informadaBackend: Kotlin, Java e Spring Boot.Frontend: JavaScript, TypeScript e React.Banco de dados: PostgreSQL e AuroraDB.Cloud e infraestrutura: AWS, EKS, ECR, SSM e S3.Testes: Cypress e Playwright.CI/CD e observabilidade: GitHub CI/CD e Datadog.Modelo de trabalhoVaga remota.Localização elegível: América do Sul, Europa ou Estados Unidos.Nível: pleno. ","permalink":"https://kotlin.dev.br/vagas/eal8no29sf9epran-team-international-desenvolvedor-a-full-stack-kotlin-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA TEAM International tem uma vaga plena remota para atuação com stack full stack, incluindo Kotlin, Java, TypeScript, React, Spring Boot, PostgreSQL e AWS.\u003c/p\u003e\u003ch3\u003eStack informada\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eBackend:\u003c/strong\u003e Kotlin, Java e Spring Boot.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eFrontend:\u003c/strong\u003e JavaScript, TypeScript e React.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eBanco de dados:\u003c/strong\u003e PostgreSQL e AuroraDB.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eCloud e infraestrutura:\u003c/strong\u003e AWS, EKS, ECR, SSM e S3.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eTestes:\u003c/strong\u003e Cypress e Playwright.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eCI/CD e observabilidade:\u003c/strong\u003e GitHub CI/CD e Datadog.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eVaga remota.\u003c/li\u003e\u003cli\u003eLocalização elegível: América do Sul, Europa ou Estados Unidos.\u003c/li\u003e\u003cli\u003eNível: pleno.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Full Stack Kotlin Pleno"},{"content":"Sobre a vagaA TEAM International busca uma pessoa desenvolvedora Pleno para atuação remota em um projeto com stack Kotlin, Spring Boot, React e TypeScript.\nRequisitosExperiência com Kotlin e Spring Boot.Experiência com TypeScript e React.Conhecimento em PostgreSQL.Experiência com serviços AWS, incluindo EKS, ECR, SSM e S3.Conhecimento em Kubernetes e Terraform.Familiaridade com ferramentas de observabilidade e colaboração como Datadog e Atlassian.DiferenciaisExperiência com ferramentas de IA para desenvolvimento, como Claude Code, Cursor e GitHub Copilot.Local de trabalhoVaga remota para profissionais na Polônia, Estados Unidos, Portugal ou América do Sul.\n","permalink":"https://kotlin.dev.br/vagas/37w87w9h7ylsdy0g-team-international-desenvolvedor-a-kotlin-full-stack-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA TEAM International busca uma pessoa desenvolvedora \u003cstrong\u003ePleno\u003c/strong\u003e para atuação remota em um projeto com stack Kotlin, Spring Boot, React e TypeScript.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eSpring Boot\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eTypeScript\u003c/strong\u003e e \u003cstrong\u003eReact\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003ePostgreSQL\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com serviços AWS, incluindo EKS, ECR, SSM e S3.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKubernetes\u003c/strong\u003e e \u003cstrong\u003eTerraform\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eFamiliaridade com ferramentas de observabilidade e colaboração como Datadog e Atlassian.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com ferramentas de IA para desenvolvimento, como Claude Code, Cursor e GitHub Copilot.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais na Polônia, Estados Unidos, Portugal ou América do Sul.\u003c/p\u003e","title":"Desenvolvedor(a) Kotlin Full Stack Pleno"},{"content":"Sobre a vagaA Stone busca uma pessoa Engenheira de Software III para atuar em soluções Mobile/Web em modelo remoto no Brasil.\nRequisitosExperiência com desenvolvimento Mobile/Web.Conhecimento em Kotlin Multiplatform e Compose Multiplatform.Experiência com APIs REST.Conhecimento em tecnologias Web como HTML, CSS e JavaScript.Experiência com React ou Vue.Vivência com práticas de CI/CD.Conhecimentos de observabilidade em aplicações.Modelo de trabalhoVaga remota para profissionais no Brasil, em nível pleno.\n","permalink":"https://kotlin.dev.br/vagas/x4v3uekelvdj6b1l-stone-engenheiro-a-de-software-iii-mobile-web/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Stone busca uma pessoa Engenheira de Software III para atuar em soluções Mobile/Web em modelo remoto no Brasil.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com desenvolvimento Mobile/Web.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin Multiplatform\u003c/strong\u003e e \u003cstrong\u003eCompose Multiplatform\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com APIs \u003cstrong\u003eREST\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em tecnologias Web como \u003cstrong\u003eHTML\u003c/strong\u003e, \u003cstrong\u003eCSS\u003c/strong\u003e e \u003cstrong\u003eJavaScript\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eReact\u003c/strong\u003e ou \u003cstrong\u003eVue\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com práticas de \u003cstrong\u003eCI/CD\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimentos de observabilidade em aplicações.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais no Brasil, em nível pleno.\u003c/p\u003e","title":"Engenheiro(a) de Software III - Mobile/Web"},{"content":"Sobre a vagaO Google busca uma pessoa Engenheira de Software de nível pleno para atuar em Qualidade do Search Live, em Belo Horizonte, Minas Gerais, com trabalho presencial.\nStack e áreas de atuaçãoKotlin e PythonFrameworks de Machine LearningImplantação de modelosProcessamento de dadosRequisitosExperiência em engenharia de software em nível pleno.Conhecimento prático em desenvolvimento com Kotlin e Python.Familiaridade com fluxos de Machine Learning, processamento de dados e deploy de modelos.Disponibilidade para atuação presencial em Belo Horizonte. ","permalink":"https://kotlin.dev.br/vagas/46533ryq3mg8sci9-google-engenheiro-a-de-software-qualidade-do-search-live/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO Google busca uma pessoa Engenheira de Software de nível pleno para atuar em Qualidade do Search Live, em Belo Horizonte, Minas Gerais, com trabalho presencial.\u003c/p\u003e\u003ch3\u003eStack e áreas de atuação\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Python\u003c/li\u003e\u003cli\u003eFrameworks de Machine Learning\u003c/li\u003e\u003cli\u003eImplantação de modelos\u003c/li\u003e\u003cli\u003eProcessamento de dados\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em engenharia de software em nível pleno.\u003c/li\u003e\u003cli\u003eConhecimento prático em desenvolvimento com Kotlin e Python.\u003c/li\u003e\u003cli\u003eFamiliaridade com fluxos de Machine Learning, processamento de dados e deploy de modelos.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação presencial em Belo Horizonte.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software, Qualidade do Search Live"},{"content":"Sobre a vagaA Accenture busca uma pessoa Especialista em Desenvolvimento Android para atuação em modelo híbrido. A vaga é de nível pleno e requer inglês avançado.\nRequisitosExperiência com desenvolvimento Android.Conhecimento em Kotlin para aplicações mobile.Inglês avançado.Disponibilidade para atuação híbrida em São Paulo, Recife, Fortaleza, Campina Grande ou Belém.Local de trabalhoModelo híbrido, com possibilidade de atuação nas cidades de São Paulo, Recife, Fortaleza, Campina Grande ou Belém.\n","permalink":"https://kotlin.dev.br/vagas/nleukeybkdu8r030-accenture-especialista-em-desenvolvimento-android-ingles-avanca/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Accenture busca uma pessoa Especialista em Desenvolvimento Android para atuação em modelo híbrido. A vaga é de nível pleno e requer inglês avançado.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin para aplicações mobile.\u003c/li\u003e\u003cli\u003eInglês avançado.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação híbrida em São Paulo, Recife, Fortaleza, Campina Grande ou Belém.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eModelo híbrido, com possibilidade de atuação nas cidades de São Paulo, Recife, Fortaleza, Campina Grande ou Belém.\u003c/p\u003e","title":"Especialista em Desenvolvimento Android – Inglês Avançado"},{"content":"Sobre a vagaA Addi busca uma pessoa Engenheira de Software Backend JVM pleno para atuar remotamente, com base em Bogotá, Colômbia.\nA posição envolve desenvolvimento de serviços backend e APIs usando tecnologias do ecossistema JVM, com foco em qualidade, escalabilidade e automação.\nResponsabilidadesDesenvolver, manter e evoluir serviços backend em JVM.Criar e integrar APIs para produtos e sistemas internos.Trabalhar com bancos de dados SQL, PostgreSQL e Redis.Implementar testes automatizados e participar de práticas de CI/CD.Atuar com mensageria e processamento assíncrono usando Kafka, SQS ou RabbitMQ.Colaborar com times de produto e engenharia em soluções escaláveis.RequisitosExperiência de nível pleno em engenharia de software backend.Conhecimento em Java, Kotlin ou Scala no ecossistema JVM.Experiência com Spring Boot.Experiência com SQL e PostgreSQL.Conhecimento em desenvolvimento de APIs e testes automatizados.Familiaridade com Docker, Kubernetes e pipelines de CI/CD.DiferenciaisExperiência com Kafka, SQS ou RabbitMQ.Vivência em ambientes distribuídos e orientados a microsserviços. ","permalink":"https://kotlin.dev.br/vagas/6bcmp1cf55apv486-addi-engenheiro-de-software-backend-jvm-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Addi busca uma pessoa Engenheira de Software Backend JVM pleno para atuar remotamente, com base em Bogotá, Colômbia.\u003c/p\u003e\u003cp\u003eA posição envolve desenvolvimento de serviços backend e APIs usando tecnologias do ecossistema JVM, com foco em qualidade, escalabilidade e automação.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver, manter e evoluir serviços backend em JVM.\u003c/li\u003e\u003cli\u003eCriar e integrar APIs para produtos e sistemas internos.\u003c/li\u003e\u003cli\u003eTrabalhar com bancos de dados SQL, PostgreSQL e Redis.\u003c/li\u003e\u003cli\u003eImplementar testes automatizados e participar de práticas de CI/CD.\u003c/li\u003e\u003cli\u003eAtuar com mensageria e processamento assíncrono usando Kafka, SQS ou RabbitMQ.\u003c/li\u003e\u003cli\u003eColaborar com times de produto e engenharia em soluções escaláveis.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência de nível pleno em engenharia de software backend.\u003c/li\u003e\u003cli\u003eConhecimento em Java, Kotlin ou Scala no ecossistema JVM.\u003c/li\u003e\u003cli\u003eExperiência com Spring Boot.\u003c/li\u003e\u003cli\u003eExperiência com SQL e PostgreSQL.\u003c/li\u003e\u003cli\u003eConhecimento em desenvolvimento de APIs e testes automatizados.\u003c/li\u003e\u003cli\u003eFamiliaridade com Docker, Kubernetes e pipelines de CI/CD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kafka, SQS ou RabbitMQ.\u003c/li\u003e\u003cli\u003eVivência em ambientes distribuídos e orientados a microsserviços.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Software Backend JVM Pleno"},{"content":"Sobre a vagaO iFood busca uma pessoa Senior Staff Software Engineer para atuação remota, com base em Osasco, São Paulo.\nStack e foco técnicoKotlin e JavaDomain-Driven DesignArquitetura de softwareObservabilidade e monitoramentoSenioridadeVaga de nível sênior, com expectativa de atuação técnica estratégica em engenharia de software.\nObservaçãoA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos ou benefícios.\n","permalink":"https://kotlin.dev.br/vagas/m4iq2pm3ryx6jusq-ifood-engenheiro-a-de-software-senior-staff/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa \u003cstrong\u003eSenior Staff Software Engineer\u003c/strong\u003e para atuação remota, com base em Osasco, São Paulo.\u003c/p\u003e\u003ch3\u003eStack e foco técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Java\u003c/li\u003e\u003cli\u003eDomain-Driven Design\u003c/li\u003e\u003cli\u003eArquitetura de software\u003c/li\u003e\u003cli\u003eObservabilidade e monitoramento\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade\u003c/h3\u003e\u003cp\u003eVaga de nível sênior, com expectativa de atuação técnica estratégica em engenharia de software.\u003c/p\u003e\u003ch3\u003eObservação\u003c/h3\u003e\u003cp\u003eA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos ou benefícios.\u003c/p\u003e","title":"Engenheiro(a) de Software Senior Staff"},{"content":"Sobre a vagaO iFood busca uma pessoa Engenheira de Software Staff Sênior para atuar em Backend em uma posição presencial no Brasil.\nTecnologiasKotlin e GoAWS e LinuxKubernetes e DockerKafka, SQS, SNS e RabbitMQFerramentas de IA como GitHub Copilot, Claude e CursorRequisitosExperiência sênior em engenharia de software backend.Vivência com sistemas distribuídos, mensageria e ambientes em nuvem.Conhecimento prático em containers, orquestração e práticas modernas de desenvolvimento. ","permalink":"https://kotlin.dev.br/vagas/5jefcqrjw10pvhb6-ifood-engenheiro-a-de-software-staff-senior-backend/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa Engenheira de Software Staff Sênior para atuar em Backend em uma posição presencial no Brasil.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Go\u003c/li\u003e\u003cli\u003eAWS e Linux\u003c/li\u003e\u003cli\u003eKubernetes e Docker\u003c/li\u003e\u003cli\u003eKafka, SQS, SNS e RabbitMQ\u003c/li\u003e\u003cli\u003eFerramentas de IA como GitHub Copilot, Claude e Cursor\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software backend.\u003c/li\u003e\u003cli\u003eVivência com sistemas distribuídos, mensageria e ambientes em nuvem.\u003c/li\u003e\u003cli\u003eConhecimento prático em containers, orquestração e práticas modernas de desenvolvimento.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Staff Sênior Backend"},{"content":"Sobre a vagaA Appstack busca uma pessoa Desenvolvedora Android Pleno para atuação remota, com base em Buenos Aires, Argentina.\nRequisitosExperiência com desenvolvimento Android.Conhecimento em Kotlin.Experiência com Jetpack Compose e layouts em XML.Modelo de trabalhoVaga remota.\n","permalink":"https://kotlin.dev.br/vagas/ywtrz5x9jk30rcda-appstack-desenvolvedor-android-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Appstack busca uma pessoa Desenvolvedora Android Pleno para atuação remota, com base em Buenos Aires, Argentina.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eJetpack Compose\u003c/strong\u003e e layouts em \u003cstrong\u003eXML\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota.\u003c/p\u003e","title":"Desenvolvedor Android Pleno"},{"content":"Sobre a vagaA CI\u0026amp;T busca uma pessoa Flutter Developer Sênior para atuação remota no Brasil em projetos mobile.\nResponsabilidadesDesenvolver e manter aplicações mobile com Flutter e Dart.Integrar aplicações com REST APIs e GraphQL.Colaborar com práticas de versionamento, integração e entrega contínua.Acompanhar qualidade, estabilidade e métricas das aplicações com ferramentas de observabilidade e crash reporting.RequisitosExperiência sênior com Flutter e Dart.Conhecimento em REST APIs e GraphQL.Experiência com Git e pipelines de CI/CD.Vivência com ferramentas como New Relic, Logz, Amplitude, Crashlytics ou Bugsnag.Conhecimento em Kotlin e Swift para integração com plataformas nativas. ","permalink":"https://kotlin.dev.br/vagas/o9clmbpu1oc15cg1-ci-t-flutter-developer-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026amp;T busca uma pessoa Flutter Developer Sênior para atuação remota no Brasil em projetos mobile.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações mobile com Flutter e Dart.\u003c/li\u003e\u003cli\u003eIntegrar aplicações com REST APIs e GraphQL.\u003c/li\u003e\u003cli\u003eColaborar com práticas de versionamento, integração e entrega contínua.\u003c/li\u003e\u003cli\u003eAcompanhar qualidade, estabilidade e métricas das aplicações com ferramentas de observabilidade e crash reporting.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com Flutter e Dart.\u003c/li\u003e\u003cli\u003eConhecimento em REST APIs e GraphQL.\u003c/li\u003e\u003cli\u003eExperiência com Git e pipelines de CI/CD.\u003c/li\u003e\u003cli\u003eVivência com ferramentas como New Relic, Logz, Amplitude, Crashlytics ou Bugsnag.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin e Swift para integração com plataformas nativas.\u003c/li\u003e\u003c/ul\u003e","title":"Flutter Developer Sênior"},{"content":"Sobre a vagaA Brex busca uma pessoa Engenheira de Software II para atuar em Credit Limit Engineering, com modelo híbrido em São Paulo, São Paulo.\nStack técnicaKotlinJavaTypeScriptPostgreSQLKafkaMicronautPerfilVaga de nível pleno para desenvolvimento de software em sistemas relacionados a limites de crédito.\n","permalink":"https://kotlin.dev.br/vagas/zi860loax9bmdi4y-brex-engenheiro-de-software-ii-limites-de-credito/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Brex busca uma pessoa Engenheira de Software II para atuar em Credit Limit Engineering, com modelo híbrido em São Paulo, São Paulo.\u003c/p\u003e\u003ch3\u003eStack técnica\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eTypeScript\u003c/li\u003e\u003cli\u003ePostgreSQL\u003c/li\u003e\u003cli\u003eKafka\u003c/li\u003e\u003cli\u003eMicronaut\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cp\u003eVaga de nível pleno para desenvolvimento de software em sistemas relacionados a limites de crédito.\u003c/p\u003e","title":"Engenheiro de Software II - Limites de Crédito"},{"content":"Sobre a vagaO iFood busca uma pessoa Engenheira de Software Flutter Sênior para atuar em produtos mobile, em modelo presencial, com localização indicada como Osasco ou Brasil.\nRequisitos e tecnologiasExperiência sênior com desenvolvimento mobile usando Flutter e Dart.Integração com APIs REST e GraphQL.Conhecimento de ecossistemas mobile nativos, incluindo Kotlin e Swift.Uso de Git e práticas de CI/CD.Experiência com observabilidade, qualidade e análise de falhas usando ferramentas como Crashlytics, Bugsnag, New Relic, Logz e Amplitude.ResponsabilidadesDesenvolver, manter e evoluir aplicações mobile em Flutter.Colaborar com times de produto, design e engenharia para entregar soluções escaláveis.Investigar bugs, melhorar estabilidade e acompanhar métricas de performance e uso.Contribuir com boas práticas de engenharia, revisão de código e automação de entrega. ","permalink":"https://kotlin.dev.br/vagas/p1tzajscnfauzeiz-ifood-engenheiro-a-de-software-flutter-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa Engenheira de Software Flutter Sênior para atuar em produtos mobile, em modelo presencial, com localização indicada como Osasco ou Brasil.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com desenvolvimento mobile usando \u003cstrong\u003eFlutter\u003c/strong\u003e e \u003cstrong\u003eDart\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eIntegração com \u003cstrong\u003eAPIs REST\u003c/strong\u003e e \u003cstrong\u003eGraphQL\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento de ecossistemas mobile nativos, incluindo \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eSwift\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eGit\u003c/strong\u003e e práticas de \u003cstrong\u003eCI/CD\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com observabilidade, qualidade e análise de falhas usando ferramentas como \u003cstrong\u003eCrashlytics\u003c/strong\u003e, \u003cstrong\u003eBugsnag\u003c/strong\u003e, \u003cstrong\u003eNew Relic\u003c/strong\u003e, \u003cstrong\u003eLogz\u003c/strong\u003e e \u003cstrong\u003eAmplitude\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver, manter e evoluir aplicações mobile em Flutter.\u003c/li\u003e\u003cli\u003eColaborar com times de produto, design e engenharia para entregar soluções escaláveis.\u003c/li\u003e\u003cli\u003eInvestigar bugs, melhorar estabilidade e acompanhar métricas de performance e uso.\u003c/li\u003e\u003cli\u003eContribuir com boas práticas de engenharia, revisão de código e automação de entrega.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Flutter Sênior"},{"content":"Sobre a vagaO iFood busca uma pessoa Engenheira de Software Flutter Sênior para atuar presencialmente em Osasco, São Paulo, no desenvolvimento de soluções mobile.\nStack e tecnologiasFlutter e DartIntegração com APIs RESTGit e práticas de CI/CDKotlin e Swift em contexto mobilePerfilVaga de nível sênior para pessoa desenvolvedora com experiência em engenharia de software mobile e colaboração com times técnicos.\n","permalink":"https://kotlin.dev.br/vagas/vx8l1e6c7hp8ttmi-ifood-engenheiro-a-de-software-flutter-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa Engenheira de Software Flutter Sênior para atuar presencialmente em Osasco, São Paulo, no desenvolvimento de soluções mobile.\u003c/p\u003e\u003ch3\u003eStack e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eFlutter e Dart\u003c/li\u003e\u003cli\u003eIntegração com APIs REST\u003c/li\u003e\u003cli\u003eGit e práticas de CI/CD\u003c/li\u003e\u003cli\u003eKotlin e Swift em contexto mobile\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cp\u003eVaga de nível sênior para pessoa desenvolvedora com experiência em engenharia de software mobile e colaboração com times técnicos.\u003c/p\u003e","title":"Engenheiro(a) de Software Flutter Sênior"},{"content":"Sobre a vagaVaga sênior presencial no C6 Bank para atuar como Especialista Backend Java e Kotlin na área de Conta Global, em São Paulo.\nResponsabilidadesDesenvolver e evoluir serviços backend para produtos financeiros.Trabalhar com arquitetura de microservices, integrações e mensageria.Colaborar com práticas de qualidade, testes e CI/CD.RequisitosExperiência sênior com Java e Kotlin.Conhecimento em Spring Boot e arquitetura de microservices.Experiência com bancos de dados como PostgreSQL, MongoDB ou Cassandra.Vivência com Kafka, SQS, SNS, JWT e OAuth2.Conhecimento em AWS, Terraform, CloudFormation e pipelines de CI/CD.Prática com testes, incluindo TDD ou BDD. ","permalink":"https://kotlin.dev.br/vagas/fshjgv2e0fqbd3sw-c6-bank-especialista-backend-java-e-kotlin-conta-global/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga sênior presencial no C6 Bank para atuar como Especialista Backend Java e Kotlin na área de Conta Global, em São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e evoluir serviços backend para produtos financeiros.\u003c/li\u003e\u003cli\u003eTrabalhar com arquitetura de microservices, integrações e mensageria.\u003c/li\u003e\u003cli\u003eColaborar com práticas de qualidade, testes e CI/CD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com Java e Kotlin.\u003c/li\u003e\u003cli\u003eConhecimento em Spring Boot e arquitetura de microservices.\u003c/li\u003e\u003cli\u003eExperiência com bancos de dados como PostgreSQL, MongoDB ou Cassandra.\u003c/li\u003e\u003cli\u003eVivência com Kafka, SQS, SNS, JWT e OAuth2.\u003c/li\u003e\u003cli\u003eConhecimento em AWS, Terraform, CloudFormation e pipelines de CI/CD.\u003c/li\u003e\u003cli\u003ePrática com testes, incluindo TDD ou BDD.\u003c/li\u003e\u003c/ul\u003e","title":"Especialista Backend Java e Kotlin | Conta Global"},{"content":"Sobre a vagaA TripleTen busca uma pessoa autora sênior em meio período para atuar com conteúdo de IA para QA, com foco em Kotlin, Mobile e contexto B2B para a Nebius Academy.\nFormato e localizaçãoModelo remoto.Localização informada: Buenos Aires, Buenos Aires, Argentina.Senioridade: sênior.Regime: meio período.Tecnologias e temas mencionadosKotlin e desenvolvimento Mobile.Ferramentas de IA aplicadas a QA.TestRigor, Magic Inspector e Rainforest QA. ","permalink":"https://kotlin.dev.br/vagas/bertd3fk766hk5gt-tripleten-autor-a-de-ia-para-qa-em-meio-periodo-kotlin-mobile/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA TripleTen busca uma pessoa autora sênior em meio período para atuar com conteúdo de IA para QA, com foco em Kotlin, Mobile e contexto B2B para a Nebius Academy.\u003c/p\u003e\u003ch3\u003eFormato e localização\u003c/h3\u003e\u003cul\u003e\u003cli\u003eModelo remoto.\u003c/li\u003e\u003cli\u003eLocalização informada: Buenos Aires, Buenos Aires, Argentina.\u003c/li\u003e\u003cli\u003eSenioridade: sênior.\u003c/li\u003e\u003cli\u003eRegime: meio período.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias e temas mencionados\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e desenvolvimento Mobile.\u003c/li\u003e\u003cli\u003eFerramentas de IA aplicadas a QA.\u003c/li\u003e\u003cli\u003eTestRigor, Magic Inspector e Rainforest QA.\u003c/li\u003e\u003c/ul\u003e","title":"Autor(a) de IA para QA em meio período (Kotlin, Mobile)"},{"content":"Sobre a vagaA TripleTen busca um(a) autor(a) sênior em meio período para criar conteúdo sobre IA aplicada a QA, com foco em Kotlin, Mobile QA e contexto B2B para a Nebius Academy.\nResponsabilidadesProduzir materiais educacionais técnicos sobre IA para QA e testes mobile.Abordar ferramentas como testRigor, Magic Inspector e Rainforest QA.Adaptar explicações e exemplos para público B2B.Colaborar remotamente com a equipe de conteúdo e revisão técnica.RequisitosExperiência sênior em QA, Mobile QA ou automação de testes.Conhecimento de Kotlin em contextos mobile.Experiência ou familiaridade com ferramentas de IA aplicadas a testes.Boa escrita técnica e capacidade de criar conteúdo claro e estruturado.Disponibilidade para atuação remota em meio período. ","permalink":"https://kotlin.dev.br/vagas/4r61my2w7iz9or8z-tripleten-autor-a-meio-periodo-de-ia-para-qa-kotlin-mobile-b2b/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA TripleTen busca um(a) autor(a) sênior em meio período para criar conteúdo sobre IA aplicada a QA, com foco em Kotlin, Mobile QA e contexto B2B para a Nebius Academy.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eProduzir materiais educacionais técnicos sobre IA para QA e testes mobile.\u003c/li\u003e\u003cli\u003eAbordar ferramentas como testRigor, Magic Inspector e Rainforest QA.\u003c/li\u003e\u003cli\u003eAdaptar explicações e exemplos para público B2B.\u003c/li\u003e\u003cli\u003eColaborar remotamente com a equipe de conteúdo e revisão técnica.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em QA, Mobile QA ou automação de testes.\u003c/li\u003e\u003cli\u003eConhecimento de Kotlin em contextos mobile.\u003c/li\u003e\u003cli\u003eExperiência ou familiaridade com ferramentas de IA aplicadas a testes.\u003c/li\u003e\u003cli\u003eBoa escrita técnica e capacidade de criar conteúdo claro e estruturado.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação remota em meio período.\u003c/li\u003e\u003c/ul\u003e","title":"Autor(a) meio período de IA para QA (Kotlin, Mobile, B2B)"},{"content":"Sobre a vagaA TripleTen busca uma pessoa sênior para atuar meio período como autor(a) de conteúdo técnico sobre IA aplicada a QA, com foco em Kotlin, Mobile e contexto B2B.\nResponsabilidadesProduzir materiais técnicos sobre QA com IA para públicos B2B.Trabalhar com exemplos e abordagens relacionados a Kotlin e desenvolvimento Mobile.Abordar ferramentas de QA mencionadas na vaga, como testRigor, Magic Inspector e Rainforest QA.RequisitosExperiência sênior em QA, automação de testes ou áreas relacionadas.Conhecimento de Kotlin e do ecossistema Mobile.Capacidade de escrever conteúdo técnico claro, estruturado e aplicável.Familiaridade com soluções de IA para testes e qualidade de software.Informações da vagaModelo: remoto.Carga: meio período.Localidade informada: Lima, Peru. ","permalink":"https://kotlin.dev.br/vagas/vv8zdajhwa9fsld2-tripleten-autor-a-meio-periodo-de-ia-para-qa-kotlin-mobile-b2b/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA TripleTen busca uma pessoa sênior para atuar meio período como autor(a) de conteúdo técnico sobre IA aplicada a QA, com foco em Kotlin, Mobile e contexto B2B.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eProduzir materiais técnicos sobre QA com IA para públicos B2B.\u003c/li\u003e\u003cli\u003eTrabalhar com exemplos e abordagens relacionados a Kotlin e desenvolvimento Mobile.\u003c/li\u003e\u003cli\u003eAbordar ferramentas de QA mencionadas na vaga, como testRigor, Magic Inspector e Rainforest QA.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em QA, automação de testes ou áreas relacionadas.\u003c/li\u003e\u003cli\u003eConhecimento de Kotlin e do ecossistema Mobile.\u003c/li\u003e\u003cli\u003eCapacidade de escrever conteúdo técnico claro, estruturado e aplicável.\u003c/li\u003e\u003cli\u003eFamiliaridade com soluções de IA para testes e qualidade de software.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eInformações da vaga\u003c/h3\u003e\u003cul\u003e\u003cli\u003eModelo: remoto.\u003c/li\u003e\u003cli\u003eCarga: meio período.\u003c/li\u003e\u003cli\u003eLocalidade informada: Lima, Peru.\u003c/li\u003e\u003c/ul\u003e","title":"Autor(a) Meio Período de IA para QA (Kotlin, Mobile, B2B)"},{"content":"Sobre a vagaA TripleTen busca um(a) autor(a) part-time sênior para produzir conteúdo técnico sobre AI para QA, com foco em Kotlin, Mobile e contexto B2B para a Nebius Academy.\nResponsabilidadesCriar materiais técnicos e educacionais sobre AI aplicada a QA.Abordar práticas de qualidade e testes em aplicações Mobile com Kotlin.Produzir conteúdo claro, estruturado e adequado para público técnico B2B.RequisitosExperiência sênior em QA, automação de testes ou qualidade de software.Conhecimento de Kotlin e desenvolvimento Mobile.Familiaridade com ferramentas de QA assistidas por IA, como testRigor, Magic Inspector ou Rainforest QA.Capacidade de escrever conteúdo técnico em formato educacional.FormatoContrato part-time.Trabalho remoto a partir de Santa Cruz de la Sierra, Bolívia. ","permalink":"https://kotlin.dev.br/vagas/t02v9mo7vecuy97i-tripleten-autor-a-part-time-de-ai-para-qa-kotlin-e-mobile/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA TripleTen busca um(a) autor(a) part-time sênior para produzir conteúdo técnico sobre AI para QA, com foco em Kotlin, Mobile e contexto B2B para a Nebius Academy.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eCriar materiais técnicos e educacionais sobre AI aplicada a QA.\u003c/li\u003e\u003cli\u003eAbordar práticas de qualidade e testes em aplicações Mobile com Kotlin.\u003c/li\u003e\u003cli\u003eProduzir conteúdo claro, estruturado e adequado para público técnico B2B.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em QA, automação de testes ou qualidade de software.\u003c/li\u003e\u003cli\u003eConhecimento de Kotlin e desenvolvimento Mobile.\u003c/li\u003e\u003cli\u003eFamiliaridade com ferramentas de QA assistidas por IA, como testRigor, Magic Inspector ou Rainforest QA.\u003c/li\u003e\u003cli\u003eCapacidade de escrever conteúdo técnico em formato educacional.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFormato\u003c/h3\u003e\u003cul\u003e\u003cli\u003eContrato part-time.\u003c/li\u003e\u003cli\u003eTrabalho remoto a partir de Santa Cruz de la Sierra, Bolívia.\u003c/li\u003e\u003c/ul\u003e","title":"Autor(a) Part-time de AI para QA (Kotlin e Mobile)"},{"content":"Sobre a vagaA CI\u0026T busca uma pessoa Desenvolvedora Back-End Sênior para atuação remota no Brasil, com foco em serviços back-end usando Kotlin, Java e Spring Boot.\nResponsabilidadesDesenvolver e manter APIs RESTful e serviços back-end escaláveis.Trabalhar com conteinerização, orquestração e ambientes em nuvem.Aplicar boas práticas de segurança no desenvolvimento de aplicações.Colaborar em pipelines de CI/CD e processos de entrega contínua.RequisitosExperiência sênior em desenvolvimento back-end.Conhecimento em Kotlin, Java e Spring Boot.Experiência com APIs RESTful.Vivência com Docker e Kubernetes.Experiência com serviços em nuvem, especialmente Azure e AWS.Conhecimento de CI/CD e boas práticas de segurança. ","permalink":"https://kotlin.dev.br/vagas/wug8ygqlkml30kq7-ci-t-desenvolvedor-a-back-end-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026T busca uma pessoa Desenvolvedora Back-End Sênior para atuação remota no Brasil, com foco em serviços back-end usando Kotlin, Java e Spring Boot.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter APIs RESTful e serviços back-end escaláveis.\u003c/li\u003e\u003cli\u003eTrabalhar com conteinerização, orquestração e ambientes em nuvem.\u003c/li\u003e\u003cli\u003eAplicar boas práticas de segurança no desenvolvimento de aplicações.\u003c/li\u003e\u003cli\u003eColaborar em pipelines de CI/CD e processos de entrega contínua.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento back-end.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Java e Spring Boot.\u003c/li\u003e\u003cli\u003eExperiência com APIs RESTful.\u003c/li\u003e\u003cli\u003eVivência com Docker e Kubernetes.\u003c/li\u003e\u003cli\u003eExperiência com serviços em nuvem, especialmente Azure e AWS.\u003c/li\u003e\u003cli\u003eConhecimento de CI/CD e boas práticas de segurança.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Back-End Sênior"},{"content":"Sobre a vagaA Experian busca uma pessoa Analista de Desenvolvimento Smart POS Pleno para atuação híbrida em Blumenau, Santa Catarina.\nResponsabilidadesDesenvolver e manter soluções para Smart POS.Integrar aplicações com APIs REST e soluções como CliSiTef.Colaborar com o time usando Git no fluxo de desenvolvimento.Acompanhar estabilidade e observabilidade com Datadog e Crashlytics.RequisitosExperiência em desenvolvimento com Java e Kotlin.Conhecimento em Flutter.Experiência com integração de APIs REST.Familiaridade com Git, Datadog e Crashlytics.Nível pleno de senioridade.Modelo de trabalhoVaga híbrida em Blumenau, Santa Catarina.\n","permalink":"https://kotlin.dev.br/vagas/5r8q2dci3d12zpl8-experian-analista-de-desenvolvimento-smart-pos-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Experian busca uma pessoa Analista de Desenvolvimento Smart POS Pleno para atuação híbrida em Blumenau, Santa Catarina.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter soluções para Smart POS.\u003c/li\u003e\u003cli\u003eIntegrar aplicações com APIs REST e soluções como CliSiTef.\u003c/li\u003e\u003cli\u003eColaborar com o time usando Git no fluxo de desenvolvimento.\u003c/li\u003e\u003cli\u003eAcompanhar estabilidade e observabilidade com Datadog e Crashlytics.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento com Java e Kotlin.\u003c/li\u003e\u003cli\u003eConhecimento em Flutter.\u003c/li\u003e\u003cli\u003eExperiência com integração de APIs REST.\u003c/li\u003e\u003cli\u003eFamiliaridade com Git, Datadog e Crashlytics.\u003c/li\u003e\u003cli\u003eNível pleno de senioridade.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga híbrida em Blumenau, Santa Catarina.\u003c/p\u003e","title":"Analista de Desenvolvimento Smart POS Pleno"},{"content":"Sobre a vagaVaga presencial para Desenvolvedor Mobile iOS Pleno na EY, em São Paulo. A atuação envolve desenvolvimento mobile com Swift, Xcode, UIKit/SwiftUI e contato com tecnologias backend como Kotlin, Java, SQL, Spring ou Quarkus.\nResponsabilidadesDesenvolver, manter e evoluir aplicações iOS.Trabalhar com Swift, Xcode e interfaces em UIKit ou SwiftUI.Integrar aplicações mobile a serviços e APIs backend.Colaborar com times técnicos em soluções que envolvam Kotlin, Java, SQL, Spring ou Quarkus.RequisitosExperiência em desenvolvimento mobile iOS em nível pleno.Conhecimento em Swift, Xcode e UIKit ou SwiftUI.Noções de HTML5, CSS3, SQL e integração com backend.Familiaridade com Kotlin, Java, Spring ou Quarkus.Disponibilidade para atuação presencial em São Paulo. ","permalink":"https://kotlin.dev.br/vagas/0jgb3nokoh9y697l-ey-desenvolvedor-mobile-ios-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga presencial para Desenvolvedor Mobile iOS Pleno na EY, em São Paulo. A atuação envolve desenvolvimento mobile com Swift, Xcode, UIKit/SwiftUI e contato com tecnologias backend como Kotlin, Java, SQL, Spring ou Quarkus.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver, manter e evoluir aplicações iOS.\u003c/li\u003e\u003cli\u003eTrabalhar com Swift, Xcode e interfaces em UIKit ou SwiftUI.\u003c/li\u003e\u003cli\u003eIntegrar aplicações mobile a serviços e APIs backend.\u003c/li\u003e\u003cli\u003eColaborar com times técnicos em soluções que envolvam Kotlin, Java, SQL, Spring ou Quarkus.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento mobile iOS em nível pleno.\u003c/li\u003e\u003cli\u003eConhecimento em Swift, Xcode e UIKit ou SwiftUI.\u003c/li\u003e\u003cli\u003eNoções de HTML5, CSS3, SQL e integração com backend.\u003c/li\u003e\u003cli\u003eFamiliaridade com Kotlin, Java, Spring ou Quarkus.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação presencial em São Paulo.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Mobile iOS Pleno"},{"content":"Sobre a vagaA EY busca uma pessoa Desenvolvedora Mobile iOS Pleno para atuar em modelo híbrido em São Paulo, São Paulo.\nRequisitosExperiência em desenvolvimento mobile iOS.Conhecimento em Swift, Xcode, UIKit e SwiftUI.Familiaridade com Kotlin, Java e SQL.Conhecimento em tecnologias web como HTML5 e CSS3.Vivência ou conhecimento em frameworks backend como Spring e Quarkus.Local de trabalhoModelo híbrido em São Paulo, São Paulo.\n","permalink":"https://kotlin.dev.br/vagas/zj9bdncpvx6mca2d-ey-desenvolvedor-mobile-ios-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA EY busca uma pessoa Desenvolvedora Mobile iOS Pleno para atuar em modelo híbrido em São Paulo, São Paulo.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento mobile iOS.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eSwift\u003c/strong\u003e, \u003cstrong\u003eXcode\u003c/strong\u003e, \u003cstrong\u003eUIKit\u003c/strong\u003e e \u003cstrong\u003eSwiftUI\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eFamiliaridade com \u003cstrong\u003eKotlin\u003c/strong\u003e, \u003cstrong\u003eJava\u003c/strong\u003e e \u003cstrong\u003eSQL\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em tecnologias web como \u003cstrong\u003eHTML5\u003c/strong\u003e e \u003cstrong\u003eCSS3\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência ou conhecimento em frameworks backend como \u003cstrong\u003eSpring\u003c/strong\u003e e \u003cstrong\u003eQuarkus\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eModelo híbrido em São Paulo, São Paulo.\u003c/p\u003e","title":"Desenvolvedor Mobile iOS Pleno"},{"content":"Sobre a vagaA CI\u0026amp;T busca uma pessoa Arquiteta Mobile Principal para atuação remota no Brasil, com foco em soluções mobile para Android e iOS.\nResponsabilidadesDefinir e evoluir arquitetura mobile para aplicações Android e iOS.Orientar decisões técnicas envolvendo Kotlin, Swift e práticas modernas de desenvolvimento mobile.Apoiar pipelines de CI/CD, publicação na App Store e Play Store.Promover práticas de segurança mobile, incluindo SAST, DAST e OWASP Mobile.Contribuir com observabilidade, otimização de custos em cloud e práticas de FinOps.RequisitosExperiência sênior ou principal em arquitetura mobile.Conhecimento sólido em Kotlin, Android, Swift e iOS.Vivência com CI/CD para aplicações mobile.Experiência com processos de publicação em lojas de aplicativos.Conhecimento em segurança mobile, observabilidade e otimização de custos. ","permalink":"https://kotlin.dev.br/vagas/wadejt3bsykindaf-ci-t-arquiteto-a-mobile-principal/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026amp;T busca uma pessoa \u003cstrong\u003eArquiteta Mobile Principal\u003c/strong\u003e para atuação remota no Brasil, com foco em soluções mobile para Android e iOS.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDefinir e evoluir arquitetura mobile para aplicações Android e iOS.\u003c/li\u003e\u003cli\u003eOrientar decisões técnicas envolvendo Kotlin, Swift e práticas modernas de desenvolvimento mobile.\u003c/li\u003e\u003cli\u003eApoiar pipelines de CI/CD, publicação na App Store e Play Store.\u003c/li\u003e\u003cli\u003ePromover práticas de segurança mobile, incluindo SAST, DAST e OWASP Mobile.\u003c/li\u003e\u003cli\u003eContribuir com observabilidade, otimização de custos em cloud e práticas de FinOps.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior ou principal em arquitetura mobile.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin, Android, Swift e iOS.\u003c/li\u003e\u003cli\u003eVivência com CI/CD para aplicações mobile.\u003c/li\u003e\u003cli\u003eExperiência com processos de publicação em lojas de aplicativos.\u003c/li\u003e\u003cli\u003eConhecimento em segurança mobile, observabilidade e otimização de custos.\u003c/li\u003e\u003c/ul\u003e","title":"Arquiteto(a) Mobile Principal"},{"content":"Sobre a vagaA CI\u0026amp;T busca uma pessoa Desenvolvedora Android Sênior para atuação remota no Brasil, trabalhando com Kotlin, Java e o ecossistema Android.\nResponsabilidadesDesenvolver e manter aplicações Android com foco em qualidade, performance e segurança.Trabalhar com arquitetura MVVM, Android Architecture Components e boas práticas de desenvolvimento mobile.Integrar aplicações com APIs GraphQL e recursos de persistência local.Colaborar em práticas de testes, incluindo JUnit, TDD e BDD.Investigar problemas usando ferramentas de inspeção de rede, Profiler, Traceview, Firebase e Crashlytics.RequisitosExperiência sênior em desenvolvimento Android.Conhecimento sólido em Kotlin, Java, Android Studio, Android SDK, Gradle e Maven.Experiência com MVVM, LiveData, Flow, Lifecycle e Android Architecture Components.Vivência com Jetpack Compose, SQLite, RxJava e GraphQL.Conhecimento em ProGuard, fundamentos de segurança e publicação/monitoramento de apps.Experiência com testes automatizados usando JUnit e práticas de TDD ou BDD.DiferenciaisExperiência com AndroidTV.Conhecimento em Bitrise, Firebase e Crashlytics.Uso avançado de ferramentas de profiling e análise de performance. ","permalink":"https://kotlin.dev.br/vagas/6mu6jei25x6ds5ut-ci-t-desenvolvedor-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026amp;T busca uma pessoa Desenvolvedora Android Sênior para atuação remota no Brasil, trabalhando com Kotlin, Java e o ecossistema Android.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android com foco em qualidade, performance e segurança.\u003c/li\u003e\u003cli\u003eTrabalhar com arquitetura MVVM, Android Architecture Components e boas práticas de desenvolvimento mobile.\u003c/li\u003e\u003cli\u003eIntegrar aplicações com APIs GraphQL e recursos de persistência local.\u003c/li\u003e\u003cli\u003eColaborar em práticas de testes, incluindo JUnit, TDD e BDD.\u003c/li\u003e\u003cli\u003eInvestigar problemas usando ferramentas de inspeção de rede, Profiler, Traceview, Firebase e Crashlytics.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin, Java, Android Studio, Android SDK, Gradle e Maven.\u003c/li\u003e\u003cli\u003eExperiência com MVVM, LiveData, Flow, Lifecycle e Android Architecture Components.\u003c/li\u003e\u003cli\u003eVivência com Jetpack Compose, SQLite, RxJava e GraphQL.\u003c/li\u003e\u003cli\u003eConhecimento em ProGuard, fundamentos de segurança e publicação/monitoramento de apps.\u003c/li\u003e\u003cli\u003eExperiência com testes automatizados usando JUnit e práticas de TDD ou BDD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com AndroidTV.\u003c/li\u003e\u003cli\u003eConhecimento em Bitrise, Firebase e Crashlytics.\u003c/li\u003e\u003cli\u003eUso avançado de ferramentas de profiling e análise de performance.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android Sênior"},{"content":"Sobre a vagaA CI\u0026amp;T busca uma pessoa Desenvolvedora Android Sênior com foco em Kotlin para atuação remota a partir de Campinas, São Paulo, Brasil.\nRequisitos e tecnologiasExperiência sênior em desenvolvimento Android.Conhecimento em Kotlin, Jetpack Compose e Hilt.Uso de Git no fluxo de desenvolvimento.Experiência com testes unitários.Familiaridade com práticas de CI/CD.Modelo de trabalhoAtuação remota.Localidade informada: Campinas, São Paulo, Brasil. ","permalink":"https://kotlin.dev.br/vagas/ktwiht7l8umztl1u-ci-t-desenvolvedor-a-android-senior-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA CI\u0026amp;T busca uma pessoa Desenvolvedora Android Sênior com foco em Kotlin para atuação remota a partir de Campinas, São Paulo, Brasil.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e, \u003cstrong\u003eJetpack Compose\u003c/strong\u003e e \u003cstrong\u003eHilt\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eUso de \u003cstrong\u003eGit\u003c/strong\u003e no fluxo de desenvolvimento.\u003c/li\u003e\u003cli\u003eExperiência com testes unitários.\u003c/li\u003e\u003cli\u003eFamiliaridade com práticas de \u003cstrong\u003eCI/CD\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAtuação remota.\u003c/li\u003e\u003cli\u003eLocalidade informada: Campinas, São Paulo, Brasil.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor(a) Android Sênior - Kotlin"},{"content":"Sobre a vagaA Bold busca uma pessoa Engenheira Android Sênior para atuar remotamente em projetos Mobile com Kotlin.\nDetalhesSenioridade: SêniorModelo de trabalho: RemotoLocalização: Bogotá, Distrito Capital de Bogotá, ColômbiaTecnologiasKotlinAndroid SDKAndroid Studio ","permalink":"https://kotlin.dev.br/vagas/ev0rbf6zpf7w9ufv-bold-engenheiro-android-senior-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Bold busca uma pessoa Engenheira Android Sênior para atuar remotamente em projetos Mobile com Kotlin.\u003c/p\u003e\u003ch3\u003eDetalhes\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eSenioridade:\u003c/strong\u003e Sênior\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eModelo de trabalho:\u003c/strong\u003e Remoto\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eLocalização:\u003c/strong\u003e Bogotá, Distrito Capital de Bogotá, Colômbia\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eAndroid SDK\u003c/li\u003e\u003cli\u003eAndroid Studio\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro Android Sênior (Kotlin)"},{"content":"Sobre a vagaO C6 Bank busca uma Pessoa Desenvolvedora Android para atuar no time de Corporate Banking Engineering, em modelo presencial em São Paulo.\nResponsabilidadesDesenvolver e manter aplicações Android para soluções de Corporate Banking.Trabalhar com Kotlin, Java e Android SDK na evolução de funcionalidades mobile.Consumir APIs REST e colaborar com práticas de CI/CD e versionamento com Git.Aplicar padrões como MVVM, Clean Architecture, LiveData, ViewModel e Coroutines.RequisitosExperiência em desenvolvimento Android.Conhecimento em Kotlin, Java, Android SDK e arquitetura de aplicações mobile.Vivência com integração de APIs REST, Git e pipelines de CI/CD.Disponibilidade para atuação presencial em São Paulo. ","permalink":"https://kotlin.dev.br/vagas/4xiu1x1tta87due1-c6-bank-pessoa-desenvolvedora-android-especialista-corporate-ba/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma Pessoa Desenvolvedora Android para atuar no time de Corporate Banking Engineering, em modelo presencial em São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android para soluções de Corporate Banking.\u003c/li\u003e\u003cli\u003eTrabalhar com Kotlin, Java e Android SDK na evolução de funcionalidades mobile.\u003c/li\u003e\u003cli\u003eConsumir APIs REST e colaborar com práticas de CI/CD e versionamento com Git.\u003c/li\u003e\u003cli\u003eAplicar padrões como MVVM, Clean Architecture, LiveData, ViewModel e Coroutines.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Java, Android SDK e arquitetura de aplicações mobile.\u003c/li\u003e\u003cli\u003eVivência com integração de APIs REST, Git e pipelines de CI/CD.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação presencial em São Paulo.\u003c/li\u003e\u003c/ul\u003e","title":"Pessoa Desenvolvedora Android Especialista | Corporate Banking"},{"content":"Sobre a vagaO Bradesco busca uma Pessoa Desenvolvedora Mobile Android e iOS Pleno para atuar em modelo híbrido em Barueri, São Paulo.\nResponsabilidadesDesenvolver e manter aplicações mobile para Android e iOS.Integrar aplicações mobile com APIs REST.Colaborar com times técnicos na evolução de funcionalidades e correções.Apoiar práticas de segurança no desenvolvimento de aplicações mobile.RequisitosExperiência em desenvolvimento Android com Kotlin.Experiência em desenvolvimento iOS com Swift.Conhecimento em integração com APIs e REST APIs.Conhecimentos de segurança aplicada a aplicações mobile.Perfil pleno para atuação em ambiente híbrido.Modelo de trabalhoVaga híbrida em Barueri, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/8r78d8c8rdnn3slh-bradesco-pessoa-desenvolvedora-mobile-android-e-ios-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO Bradesco busca uma Pessoa Desenvolvedora Mobile Android e iOS Pleno para atuar em modelo híbrido em Barueri, São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações mobile para Android e iOS.\u003c/li\u003e\u003cli\u003eIntegrar aplicações mobile com APIs REST.\u003c/li\u003e\u003cli\u003eColaborar com times técnicos na evolução de funcionalidades e correções.\u003c/li\u003e\u003cli\u003eApoiar práticas de segurança no desenvolvimento de aplicações mobile.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento Android com Kotlin.\u003c/li\u003e\u003cli\u003eExperiência em desenvolvimento iOS com Swift.\u003c/li\u003e\u003cli\u003eConhecimento em integração com APIs e REST APIs.\u003c/li\u003e\u003cli\u003eConhecimentos de segurança aplicada a aplicações mobile.\u003c/li\u003e\u003cli\u003ePerfil pleno para atuação em ambiente híbrido.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga híbrida em Barueri, São Paulo, Brasil.\u003c/p\u003e","title":"Pessoa Desenvolvedora Mobile Android e iOS Pleno"},{"content":"Sobre a vagaVaga sênior para Tech Lead PIX na Getnet, com atuação presencial em São Paulo, São Paulo.\nStack e contexto técnicoJava, Kotlin e Spring Boot.Arquiteturas REST e integrações com mensageria.Cloud em AWS, Azure ou GCP.Containers com Docker e orquestração com Kubernetes.Observabilidade com Datadog e OpenTelemetry.Práticas de CI/CD e versionamento com Git.RequisitosExperiência em liderança técnica de times ou iniciativas de engenharia.Vivência sênior em desenvolvimento backend para sistemas críticos.Conhecimento em Kafka, RabbitMQ, APIs REST e ambientes cloud.Capacidade de orientar decisões técnicas, revisar soluções e apoiar a evolução da arquitetura. ","permalink":"https://kotlin.dev.br/vagas/wjiq6sksvvfqaq55-getnet-tech-lead-pix/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga sênior para \u003cstrong\u003eTech Lead PIX\u003c/strong\u003e na Getnet, com atuação presencial em São Paulo, São Paulo.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eJava, Kotlin e Spring Boot.\u003c/li\u003e\u003cli\u003eArquiteturas REST e integrações com mensageria.\u003c/li\u003e\u003cli\u003eCloud em AWS, Azure ou GCP.\u003c/li\u003e\u003cli\u003eContainers com Docker e orquestração com Kubernetes.\u003c/li\u003e\u003cli\u003eObservabilidade com Datadog e OpenTelemetry.\u003c/li\u003e\u003cli\u003ePráticas de CI/CD e versionamento com Git.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em liderança técnica de times ou iniciativas de engenharia.\u003c/li\u003e\u003cli\u003eVivência sênior em desenvolvimento backend para sistemas críticos.\u003c/li\u003e\u003cli\u003eConhecimento em Kafka, RabbitMQ, APIs REST e ambientes cloud.\u003c/li\u003e\u003cli\u003eCapacidade de orientar decisões técnicas, revisar soluções e apoiar a evolução da arquitetura.\u003c/li\u003e\u003c/ul\u003e","title":"Tech Lead PIX"},{"content":"Sobre a vagaO iFood busca uma pessoa Engenheira de Software Sênior para atuação remota no Brasil.\nTecnologias mencionadasKotlinSpringJavaGoTypeScriptJavaScriptFormato de trabalhoRemoto no BrasilNível sênior ","permalink":"https://kotlin.dev.br/vagas/ttd0mrm7vylbg5ec-ifood-engenheiro-de-software-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa Engenheira de Software Sênior para atuação remota no Brasil.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eSpring\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eGo\u003c/li\u003e\u003cli\u003eTypeScript\u003c/li\u003e\u003cli\u003eJavaScript\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFormato de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eRemoto no Brasil\u003c/li\u003e\u003cli\u003eNível sênior\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Software Sênior"},{"content":"Sobre a vagaA iFood busca uma pessoa Engenheira de Software Sênior para atuação remota no Brasil.\nStack mencionadaKotlinSpringJavaGoTypeScriptJavaScriptSenioridadeNível sênior.\n","permalink":"https://kotlin.dev.br/vagas/xx1v73lzhqpl0dwn-ifood-engenheiro-de-software-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA iFood busca uma pessoa Engenheira de Software Sênior para atuação remota no Brasil.\u003c/p\u003e\u003ch3\u003eStack mencionada\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eSpring\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eGo\u003c/li\u003e\u003cli\u003eTypeScript\u003c/li\u003e\u003cli\u003eJavaScript\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade\u003c/h3\u003e\u003cp\u003eNível sênior.\u003c/p\u003e","title":"Engenheiro de Software Sênior"},{"content":"Sobre a vagaA WatchGuard Technologies busca uma pessoa Engenheira de Software Mobile de nível pleno para atuação presencial em Santa Rita do Sapucaí ou São Paulo.\nTecnologias mencionadasKotlinSwiftJavaObjective-CFormato e localizaçãoModelo: presencialLocal: Santa Rita do Sapucaí ou São PauloSenioridade: pleno ","permalink":"https://kotlin.dev.br/vagas/nw7fdakkvam5tpwz-watchguard-technolog-engenheiro-a-de-software-mobile/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA WatchGuard Technologies busca uma pessoa \u003cstrong\u003eEngenheira de Software Mobile\u003c/strong\u003e de nível pleno para atuação presencial em Santa Rita do Sapucaí ou São Paulo.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eSwift\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eObjective-C\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFormato e localização\u003c/h3\u003e\u003cul\u003e\u003cli\u003eModelo: presencial\u003c/li\u003e\u003cli\u003eLocal: Santa Rita do Sapucaí ou São Paulo\u003c/li\u003e\u003cli\u003eSenioridade: pleno\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Mobile"},{"content":"Sobre a vagaA DoorDash busca pessoa estagiária em Engenharia de Software para atuar em modelo híbrido em São Paulo, São Paulo.\nRequisitosSem experiência prévia exigida.Interesse em desenvolvimento de software e engenharia de produto.Conhecimento ou familiaridade com Kotlin, Java, Python, SQL, AWS e Git.Modelo de trabalhoHíbrido em São Paulo, São Paulo. ","permalink":"https://kotlin.dev.br/vagas/9fpfkbjsb7lhtt15-doordash-estagio-em-engenharia-de-software/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA DoorDash busca pessoa estagiária em Engenharia de Software para atuar em modelo híbrido em São Paulo, São Paulo.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eSem experiência prévia exigida.\u003c/li\u003e\u003cli\u003eInteresse em desenvolvimento de software e engenharia de produto.\u003c/li\u003e\u003cli\u003eConhecimento ou familiaridade com Kotlin, Java, Python, SQL, AWS e Git.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eHíbrido em São Paulo, São Paulo.\u003c/li\u003e\u003c/ul\u003e","title":"Estágio em Engenharia de Software"},{"content":"Sobre a vagaA DoorDash busca pessoa estagiária em Engenharia de Software para uma vaga exclusiva para PCD em São Paulo, com modelo híbrido.\nRequisitosVaga exclusiva para pessoas com deficiência (PCD).Não é exigida experiência prévia.Conhecimento ou interesse em desenvolvimento de software com Kotlin, Java, Python e SQL.Familiaridade com Git e AWS é desejável.Modelo de trabalhoHíbrido em São Paulo, São Paulo, Brasil. ","permalink":"https://kotlin.dev.br/vagas/ofaviu5ik149ckvd-doordash-estagio-em-engenharia-de-software-vaga-exclusiva-para/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA DoorDash busca pessoa estagiária em Engenharia de Software para uma vaga exclusiva para PCD em São Paulo, com modelo híbrido.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eVaga exclusiva para pessoas com deficiência (PCD).\u003c/li\u003e\u003cli\u003eNão é exigida experiência prévia.\u003c/li\u003e\u003cli\u003eConhecimento ou interesse em desenvolvimento de software com Kotlin, Java, Python e SQL.\u003c/li\u003e\u003cli\u003eFamiliaridade com Git e AWS é desejável.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eHíbrido em São Paulo, São Paulo, Brasil.\u003c/li\u003e\u003c/ul\u003e","title":"Estágio em Engenharia de Software - Vaga exclusiva para PCD"},{"content":"Sobre a vagaA DoorDash busca uma pessoa para estágio em Engenharia de Software em São Paulo, em modelo híbrido. Esta é uma vaga afirmativa para mulheres.\nPerfilNão é exigida experiência profissional prévia.Interesse em desenvolvimento de software e aprendizado em um ambiente técnico.Tecnologias mencionadasKotlinJavaPythonSQLAWSGit ","permalink":"https://kotlin.dev.br/vagas/r6ji89gsy5gdqmb5-doordash-estagio-em-engenharia-de-software-vaga-para-mulheres/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA DoorDash busca uma pessoa para estágio em Engenharia de Software em São Paulo, em modelo híbrido. Esta é uma vaga afirmativa para mulheres.\u003c/p\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cul\u003e\u003cli\u003eNão é exigida experiência profissional prévia.\u003c/li\u003e\u003cli\u003eInteresse em desenvolvimento de software e aprendizado em um ambiente técnico.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003ePython\u003c/li\u003e\u003cli\u003eSQL\u003c/li\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eGit\u003c/li\u003e\u003c/ul\u003e","title":"Estágio em Engenharia de Software (vaga para mulheres)"},{"content":"Sobre a vagaA Bellroy busca uma pessoa Engenheira de Software de nível pleno para atuar remotamente com foco em programação funcional. A posição é aberta para Collingwood ou Brasil.\nStack e contexto técnicoLinguagens e ecossistemas mencionados: Kotlin, Haskell, Clojure, Elixir, F#, Scala, OCaml, Erlang, Rust, Swift e Ruby on Rails.Infraestrutura e ferramentas: AWS e Nix.RequisitosExperiência como pessoa desenvolvedora de software em nível pleno.Vivência com programação funcional e interesse em trabalhar em ambientes poliglotas.Capacidade de colaborar de forma remota com equipes distribuídas. ","permalink":"https://kotlin.dev.br/vagas/erdu1sl82w0643qb-bellroy-engenheiro-de-software-programacao-funcional/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Bellroy busca uma pessoa Engenheira de Software de nível pleno para atuar remotamente com foco em programação funcional. A posição é aberta para Collingwood ou Brasil.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLinguagens e ecossistemas mencionados: Kotlin, Haskell, Clojure, Elixir, F#, Scala, OCaml, Erlang, Rust, Swift e Ruby on Rails.\u003c/li\u003e\u003cli\u003eInfraestrutura e ferramentas: AWS e Nix.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência como pessoa desenvolvedora de software em nível pleno.\u003c/li\u003e\u003cli\u003eVivência com programação funcional e interesse em trabalhar em ambientes poliglotas.\u003c/li\u003e\u003cli\u003eCapacidade de colaborar de forma remota com equipes distribuídas.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Software - Programação Funcional"},{"content":"Sobre a vagaA GoDaddy busca uma pessoa Engenheira de Software Android de nível pleno para atuar remotamente na Colômbia.\nStack técnicaKotlin e Java para desenvolvimento Android.Jetpack, Coroutines, Room e Retrofit.Git para controle de versão.RequisitosExperiência com desenvolvimento de aplicativos Android.Conhecimento prático em Kotlin e Java.Familiaridade com bibliotecas e ferramentas modernas do ecossistema Android. ","permalink":"https://kotlin.dev.br/vagas/lrc68898g7p4jabt-godaddy-engenheiro-de-software-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA GoDaddy busca uma pessoa Engenheira de Software Android de nível pleno para atuar remotamente na Colômbia.\u003c/p\u003e\u003ch3\u003eStack técnica\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Java para desenvolvimento Android.\u003c/li\u003e\u003cli\u003eJetpack, Coroutines, Room e Retrofit.\u003c/li\u003e\u003cli\u003eGit para controle de versão.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com desenvolvimento de aplicativos Android.\u003c/li\u003e\u003cli\u003eConhecimento prático em Kotlin e Java.\u003c/li\u003e\u003cli\u003eFamiliaridade com bibliotecas e ferramentas modernas do ecossistema Android.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Software Android"},{"content":"Sobre a vagaO C6 Bank busca uma pessoa Engenheira de Segurança Sênior para atuar presencialmente em São Paulo nos squads Atom Security.\nAtuação e tecnologiasAtuação em engenharia de segurança cibernética em ambiente bancário.Trabalho com provedores de nuvem como AWS, GCP, Azure e OCI.Uso de SIEM e ferramentas de automação e infraestrutura como código, incluindo Ansible, Terraform e CFEngine.Integrações e padrões de identidade como SAML, OIDC e SCIM.Desenvolvimento e automação com Python, Go, Shell, Java e Kotlin.RequisitosExperiência sênior em segurança cibernética.Conhecimento prático em ambientes cloud e automação.Capacidade de atuar em squads técnicos e colaborar com times de engenharia.Local de trabalhoVaga presencial em São Paulo, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/rl6pgbd6vtixtk5a-c6-bank-engenheiro-a-de-seguranca-senior-atom-security-squads/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO C6 Bank busca uma pessoa Engenheira de Segurança Sênior para atuar presencialmente em São Paulo nos squads Atom Security.\u003c/p\u003e\u003ch3\u003eAtuação e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAtuação em engenharia de segurança cibernética em ambiente bancário.\u003c/li\u003e\u003cli\u003eTrabalho com provedores de nuvem como AWS, GCP, Azure e OCI.\u003c/li\u003e\u003cli\u003eUso de SIEM e ferramentas de automação e infraestrutura como código, incluindo Ansible, Terraform e CFEngine.\u003c/li\u003e\u003cli\u003eIntegrações e padrões de identidade como SAML, OIDC e SCIM.\u003c/li\u003e\u003cli\u003eDesenvolvimento e automação com Python, Go, Shell, Java e Kotlin.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em segurança cibernética.\u003c/li\u003e\u003cli\u003eConhecimento prático em ambientes cloud e automação.\u003c/li\u003e\u003cli\u003eCapacidade de atuar em squads técnicos e colaborar com times de engenharia.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em São Paulo, São Paulo, Brasil.\u003c/p\u003e","title":"Engenheiro(a) de Segurança Sênior | Atom Security Squads"},{"content":"Sobre a vagaA Stone busca uma pessoa Engenheira de Software III - Mobile, de nível pleno, para atuação remota no Brasil.\nTecnologias mencionadasKotlin, Jetpack Compose, Android Studio e Gradle.Firebase, JUnit, Espresso, Mockito, XCTest e Snapshot Testing.CI/CD, Fastlane, CocoaPods, Carthage e SPM.React Native e Go.ObservaçãoA descrição completa da vaga não foi informada no anúncio original.\n","permalink":"https://kotlin.dev.br/vagas/sqn74vigociodl69-stone-engenheiro-a-de-software-iii-mobile/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Stone busca uma pessoa Engenheira de Software III - Mobile, de nível pleno, para atuação remota no Brasil.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Jetpack Compose, Android Studio e Gradle.\u003c/li\u003e\u003cli\u003eFirebase, JUnit, Espresso, Mockito, XCTest e Snapshot Testing.\u003c/li\u003e\u003cli\u003eCI/CD, Fastlane, CocoaPods, Carthage e SPM.\u003c/li\u003e\u003cli\u003eReact Native e Go.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eObservação\u003c/h3\u003e\u003cp\u003eA descrição completa da vaga não foi informada no anúncio original.\u003c/p\u003e","title":"Engenheiro(a) de Software III - Mobile"},{"content":"Sobre a vagaA Backblaze busca uma pessoa Engenheira de Software Sênior para atuar remotamente na Argentina, Colômbia, Costa Rica ou México.\nStack técnicaKotlin e JavaMySQL e VitessDocker e KubernetesgRPC e Protocol BuffersReact e TypeScriptFormatoRemotoNível sênior ","permalink":"https://kotlin.dev.br/vagas/udx5u9q00n34m4yx-backblaze-engenheiro-a-de-software-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Backblaze busca uma pessoa Engenheira de Software Sênior para atuar remotamente na Argentina, Colômbia, Costa Rica ou México.\u003c/p\u003e\u003ch3\u003eStack técnica\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Java\u003c/li\u003e\u003cli\u003eMySQL e Vitess\u003c/li\u003e\u003cli\u003eDocker e Kubernetes\u003c/li\u003e\u003cli\u003egRPC e Protocol Buffers\u003c/li\u003e\u003cli\u003eReact e TypeScript\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFormato\u003c/h3\u003e\u003cul\u003e\u003cli\u003eRemoto\u003c/li\u003e\u003cli\u003eNível sênior\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Sênior"},{"content":"Sobre a vagaO iFood busca uma pessoa Engenheira de Software Android Sênior para atuação presencial em Osasco, São Paulo. A vaga envolve desenvolvimento mobile Android com Kotlin e tecnologias de pagamento.\nResponsabilidadesDesenvolver e manter soluções Android usando Kotlin.Trabalhar com integrações de SDKs e tecnologias como NFC, EMV, ISO 8583, TEF, mPOS e SmartPOS.Contribuir para arquitetura mobile com MVVM, Clean Architecture e injeção de dependência.Apoiar práticas de CI/CD, testes e qualidade de código.Atuar em soluções que exigem segurança e conformidade, incluindo PCI DSS.RequisitosExperiência sênior em desenvolvimento Android.Conhecimento sólido em Kotlin.Vivência com arquitetura mobile, testes, CI/CD e integração de SDKs.Experiência ou familiaridade com meios de pagamento, TEF, mPOS, SmartPOS, NFC, EMV ou ISO 8583.DiferenciaisExperiência com Flutter.Conhecimento em ambientes regulados por PCI DSS. ","permalink":"https://kotlin.dev.br/vagas/wrj4zgmoo35ejs0o-ifood-engenheiro-de-software-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa Engenheira de Software Android Sênior para atuação presencial em Osasco, São Paulo. A vaga envolve desenvolvimento mobile Android com Kotlin e tecnologias de pagamento.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter soluções Android usando Kotlin.\u003c/li\u003e\u003cli\u003eTrabalhar com integrações de SDKs e tecnologias como NFC, EMV, ISO 8583, TEF, mPOS e SmartPOS.\u003c/li\u003e\u003cli\u003eContribuir para arquitetura mobile com MVVM, Clean Architecture e injeção de dependência.\u003c/li\u003e\u003cli\u003eApoiar práticas de CI/CD, testes e qualidade de código.\u003c/li\u003e\u003cli\u003eAtuar em soluções que exigem segurança e conformidade, incluindo PCI DSS.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin.\u003c/li\u003e\u003cli\u003eVivência com arquitetura mobile, testes, CI/CD e integração de SDKs.\u003c/li\u003e\u003cli\u003eExperiência ou familiaridade com meios de pagamento, TEF, mPOS, SmartPOS, NFC, EMV ou ISO 8583.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Flutter.\u003c/li\u003e\u003cli\u003eConhecimento em ambientes regulados por PCI DSS.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Software Android Sênior"},{"content":"Sobre a vagaA Skeelo busca uma pessoa Engenheira Mobile Sênior com foco em Android. A vaga é remota para profissionais no Brasil.\nStack e conhecimentosKotlin, Android SDK e Jetpack Compose.Arquiteturas MVVM, MVI e Clean Architecture.Kotlin Coroutines e RxJava.Injeção de dependência com Koin e Dagger Hilt.Persistência local com Room e SQLite.Integrações com Retrofit, OkHttp, Firebase, Google Maps e Analytics.CI/CD com Jenkins, GitHub Actions e Bitrise.RequisitosExperiência sênior em desenvolvimento Android.Conhecimento prático em Kotlin e no ecossistema Android moderno.Capacidade de trabalhar em ambiente remoto. ","permalink":"https://kotlin.dev.br/vagas/83kyj84ggvgzv7w6-skeelo-engenheiro-a-mobile-senior-android/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Skeelo busca uma pessoa Engenheira Mobile Sênior com foco em Android. A vaga é remota para profissionais no Brasil.\u003c/p\u003e\u003ch3\u003eStack e conhecimentos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Android SDK e Jetpack Compose.\u003c/li\u003e\u003cli\u003eArquiteturas MVVM, MVI e Clean Architecture.\u003c/li\u003e\u003cli\u003eKotlin Coroutines e RxJava.\u003c/li\u003e\u003cli\u003eInjeção de dependência com Koin e Dagger Hilt.\u003c/li\u003e\u003cli\u003ePersistência local com Room e SQLite.\u003c/li\u003e\u003cli\u003eIntegrações com Retrofit, OkHttp, Firebase, Google Maps e Analytics.\u003c/li\u003e\u003cli\u003eCI/CD com Jenkins, GitHub Actions e Bitrise.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento prático em Kotlin e no ecossistema Android moderno.\u003c/li\u003e\u003cli\u003eCapacidade de trabalhar em ambiente remoto.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) Mobile Sênior (Android)"},{"content":"Se voce ja entende o basico de coroutines em Kotlin — launch, async, suspend — e hora de dominar os padroes avancados que separam codigo de producao de codigo de tutorial. Structured concurrency e o principio fundamental que garante que coroutines nao vazem, excecoes nao sejam silenciadas e recursos sejam liberados de forma previsivel.\nNeste artigo, vamos explorar na pratica: hierarquia de Jobs, coroutineScope vs supervisorScope, propagacao de excecoes, cancelamento cooperativo e como testar tudo isso com runTest.\nO principio da structured concurrency Structured concurrency significa que toda coroutine tem um escopo bem definido e um pai. Quando o pai e cancelado, todos os filhos sao cancelados automaticamente. Quando um filho falha, o pai e notificado. Nao existem coroutines orfas.\nEsse contrato e garantido pela hierarquia de Job. Cada CoroutineScope tem um Job pai, e cada launch ou async cria um Job filho:\nimport kotlinx.coroutines.* fun main() = runBlocking { val parentJob = coroutineContext[Job] println(\u0026#34;Filhos antes: ${parentJob?.children?.count()}\u0026#34;) launch { delay(1000) println(\u0026#34;Coroutine 1 concluida\u0026#34;) } launch { delay(500) println(\u0026#34;Coroutine 2 concluida\u0026#34;) } println(\u0026#34;Filhos depois: ${parentJob?.children?.count()}\u0026#34;) } Esse codigo imprime 2 filhos ativos. O runBlocking so termina quando ambos completam. Nenhuma coroutine escapa do escopo — esse e o contrato fundamental.\ncoroutineScope vs supervisorScope A diferenca entre esses dois builders define como falhas se propagam:\ncoroutineScope: se qualquer filho falha, todos os outros filhos sao cancelados e a excecao e relancada. supervisorScope: se um filho falha, os outros continuam executando. A falha nao se propaga automaticamente. Veja a diferenca na pratica:\nimport kotlinx.coroutines.* suspend fun fetchDashboardData() = supervisorScope { val userDeferred = async { fetchUserProfile() } val notificationsDeferred = async { fetchNotifications() } val analyticsDeferred = async { fetchAnalytics() } val user = userDeferred.await() val notifications = try { notificationsDeferred.await() } catch (e: Exception) { println(\u0026#34;Notificacoes indisponiveis: ${e.message}\u0026#34;) emptyList() } val analytics = try { analyticsDeferred.await() } catch (e: Exception) { println(\u0026#34;Analytics indisponivel: ${e.message}\u0026#34;) null } DashboardData(user, notifications, analytics) } Com supervisorScope, se fetchNotifications() falhar, o perfil do usuario e os analytics continuam carregando normalmente. Se usassemos coroutineScope, a falha nas notificacoes cancelaria todas as outras chamadas — comportamento indesejado em um dashboard.\nEsse padrao e especialmente util em APIs construidas com Ktor, onde multiplas chamadas a servicos externos acontecem em paralelo.\nTratamento de excecoes e CoroutineExceptionHandler Excecoes em coroutines seguem regras diferentes de codigo sincrono. Um try/catch dentro de launch captura a excecao normalmente, mas nao impede que ela se propague pela hierarquia de Jobs.\nPara capturar excecoes nao tratadas no nivel do escopo, use CoroutineExceptionHandler:\nimport kotlinx.coroutines.* val handler = CoroutineExceptionHandler { context, exception -\u0026gt; println(\u0026#34;Excecao capturada: ${exception.message}\u0026#34;) // Enviar para sistema de observabilidade } fun main() = runBlocking { val scope = CoroutineScope(SupervisorJob() + handler + Dispatchers.Default) scope.launch { throw RuntimeException(\u0026#34;Falha no processamento\u0026#34;) } scope.launch { delay(100) println(\u0026#34;Esta coroutine continua executando\u0026#34;) } delay(200) scope.cancel() } O CoroutineExceptionHandler funciona como uma rede de seguranca. Ele so captura excecoes que nao foram tratadas por try/catch e so funciona com launch (nao com async, onde a excecao e armazenada no Deferred). Para observabilidade em producao, integrar o handler com ferramentas de tracing e essencial.\nCancelamento cooperativo O cancelamento em coroutines e cooperativo. Isso significa que uma coroutine so e cancelada se ela verifica o status de cancelamento. Funcoes como delay(), yield() e as operacoes de I/O de kotlinx.coroutines fazem essa verificacao automaticamente.\nPara loops de processamento intensivo, voce precisa verificar manualmente:\nimport kotlinx.coroutines.* suspend fun processLargeDataset(items: List\u0026lt;DataItem\u0026gt;) = coroutineScope { items.forEachIndexed { index, item -\u0026gt; ensureActive() // Verifica cancelamento a cada iteracao processItem(item) if (index % 100 == 0) { yield() // Cede o thread para outras coroutines } } } Sem ensureActive() ou yield(), a coroutine ignora requisicoes de cancelamento e continua executando ate o fim — desperdicando recursos. Esse e um dos padroes de design mais importantes para codigo assincrono robusto.\nTrocando contexto com withContext O withContext troca o dispatcher sem criar uma nova coroutine. E a forma idiomatica de mover trabalho para um thread diferente:\nimport kotlinx.coroutines.* suspend fun loadAndParseFile(path: String): ParsedData { val rawBytes = withContext(Dispatchers.IO) { File(path).readBytes() } val parsed = withContext(Dispatchers.Default) { parseComplexFormat(rawBytes) } return parsed } Dispatchers.IO e otimizado para operacoes de I/O bloqueantes (leitura de arquivo, chamadas de rede). Dispatchers.Default usa um pool com tamanho igual ao numero de cores da CPU, ideal para processamento intensivo. Nunca faca I/O bloqueante no Dispatchers.Main ou Dispatchers.Default.\nTratamento de erros em Flows Kotlin Flow herda os principios de structured concurrency, mas tem operadores especificos para tratamento de erros:\nimport kotlinx.coroutines.delay import kotlinx.coroutines.flow.* fun fetchPricesFlow(): Flow\u0026lt;Double\u0026gt; = flow { while (true) { val price = fetchCurrentPrice() emit(price) delay(5000) } }.retry(retries = 3) { cause -\u0026gt; cause is java.io.IOException }.catch { e -\u0026gt; println(\u0026#34;Stream encerrado: ${e.message}\u0026#34;) emit(-1.0) // Valor sentinela } O operador retry re-executa o bloco flow quando a excecao corresponde ao predicado. O catch captura qualquer excecao que passe pelo retry e permite emitir um valor final antes de encerrar o stream.\nTestando coroutines com runTest O kotlinx-coroutines-test fornece runTest, que executa coroutines em tempo virtual — sem esperar delay() reais:\nimport kotlinx.coroutines.test.* import kotlin.test.Test import kotlin.test.assertEquals class DashboardServiceTest { @Test fun `deve retornar dashboard mesmo com falha parcial`() = runTest { val service = DashboardService( userApi = FakeUserApi(), notificationApi = FailingNotificationApi(), analyticsApi = FakeAnalyticsApi() ) val result = service.fetchDashboardData() assertEquals(\u0026#34;Joao\u0026#34;, result.user.name) assertEquals(emptyList(), result.notifications) } } O runTest avanca o tempo virtual automaticamente quando encontra delay(). Para cenarios onde voce precisa controlar o tempo manualmente, use advanceTimeBy() e advanceUntilIdle(). Para mais detalhes sobre testes em Kotlin com JUnit5 e MockK, confira nosso guia dedicado.\nBoas praticas para producao Nunca use GlobalScope — ele cria coroutines sem pai, quebrando structured concurrency. Prefira supervisorScope em pontos de entrada como handlers HTTP ou processadores de filas. Sempre use ensureActive() em loops longos para respeitar cancelamento. Injete dispatchers via parametro para facilitar testes. Trate excecoes no nivel mais proximo possivel antes de deixar o CoroutineExceptionHandler como ultima defesa. Desenvolvedores que trabalham com concorrencia em outras linguagens encontram paralelos interessantes. Em Go, goroutines com errgroup oferecem structured concurrency similar ao coroutineScope, mas sem hierarquia automatica de cancelamento. Em Python, o asyncio.TaskGroup introduzido no Python 3.11 se inspirou diretamente nos mesmos principios de structured concurrency do Kotlin.\nConclusao Structured concurrency nao e apenas um conceito teorico — e o alicerce que torna coroutines seguras para producao. Dominar coroutineScope, supervisorScope, cancelamento cooperativo e runTest transforma a forma como voce escreve codigo assincrono em Kotlin. Aplique esses padroes no seu proximo projeto e veja a diferenca na robustez e testabilidade do codigo.\nPerguntas frequentes Qual a diferenca entre coroutineScope e supervisorScope? O coroutineScope cancela todos os filhos quando um deles falha, e a excecao e relancada. O supervisorScope permite que os demais filhos continuem executando mesmo quando um falha, ideal para cenarios como dashboards e chamadas paralelas independentes.\nPor que nao devo usar GlobalScope? O GlobalScope cria coroutines sem pai na hierarquia de Jobs, o que significa que elas nao sao canceladas automaticamente quando o escopo que as criou termina. Isso pode causar vazamento de coroutines e comportamento imprevisivel.\nComo testar funcoes suspend que usam delay? Use runTest do pacote kotlinx-coroutines-test. Ele executa coroutines em tempo virtual, avancando automaticamente os delays sem esperar tempo real. Para controle fino, use advanceTimeBy() e advanceUntilIdle().\nO CoroutineExceptionHandler substitui try/catch? Nao. O CoroutineExceptionHandler e uma rede de seguranca para excecoes nao tratadas em coroutines lancadas com launch. Voce deve usar try/catch para tratamento local e especifico. O handler serve como ultima defesa para evitar crashes silenciosos.\nSe você quer explorar modelos de concorrência em outras linguagens, Go oferece goroutines com structured concurrency via errgroup, Rust usa async/await com Tokio e supervisão explícita e Zig oferece async com controle manual de alocação.\n","permalink":"https://kotlin.dev.br/blog/coroutines-avancadas-structured-concurrency-kotlin/","summary":"\u003cp\u003eSe voce ja entende o basico de \u003ca href=\"/blog/coroutines-kotlin/\"\u003ecoroutines em Kotlin\u003c/a\u003e — \u003ccode\u003elaunch\u003c/code\u003e, \u003ccode\u003easync\u003c/code\u003e, \u003ccode\u003esuspend\u003c/code\u003e — e hora de dominar os padroes avancados que separam codigo de producao de codigo de tutorial. Structured concurrency e o principio fundamental que garante que coroutines nao vazem, excecoes nao sejam silenciadas e recursos sejam liberados de forma previsivel.\u003c/p\u003e\n\u003cp\u003eNeste artigo, vamos explorar na pratica: hierarquia de Jobs, \u003ccode\u003ecoroutineScope\u003c/code\u003e vs \u003ccode\u003esupervisorScope\u003c/code\u003e, propagacao de excecoes, cancelamento cooperativo e como testar tudo isso com \u003ccode\u003erunTest\u003c/code\u003e.\u003c/p\u003e","title":"Coroutines Avancadas: Structured Concurrency Kotlin"},{"content":"A desestruturação é um dos recursos mais usados no Kotlin. Toda vez que você escreve val (nome, idade) = pessoa, está usando esse mecanismo. O problema é que, até agora, a desestruturação dependia exclusivamente da posição dos componentes — e isso gerava bugs sutis que só apareciam em produção.\nA partir do Kotlin 2.3.20, o compilador introduziu a desestruturação por nome (name-based destructuring) como recurso experimental. A proposta KEEP-0438 define uma mudança fundamental na forma como o Kotlin resolve variáveis em declarações de desestruturação, trazendo segurança semântica sem sacrificar a ergonomia da linguagem.\nNeste artigo, vamos explorar o problema que motivou essa mudança, a nova sintaxe, exemplos práticos e como preparar seu código para a migração.\nO problema da desestruturação por posição Considere esta data class simples:\ndata class Pessoa(val nome: String, val endereco: String) val (cidade, nome) = Pessoa(\u0026#34;João\u0026#34;, \u0026#34;Amsterdã\u0026#34;) Esse código compila sem erros. Mas cidade recebe \u0026quot;João\u0026quot; e nome recebe \u0026quot;Amsterdã\u0026quot; — exatamente o oposto do que os nomes das variáveis sugerem. O compilador não se importa com os nomes porque a desestruturação atual usa funções component1(), component2(), etc., que dependem exclusivamente da ordem.\nQuando o bug aparece de verdade O cenário mais perigoso acontece quando alguém adiciona uma propriedade no meio de uma data class:\n// Versão 1 data class Transacao(val valor: Double, val descricao: String) val (valor, descricao) = transacao // OK // Versão 2 — alguém adiciona \u0026#39;tipo\u0026#39; entre valor e descricao data class Transacao(val valor: Double, val tipo: String, val descricao: String) val (valor, descricao) = transacao // QUEBROU: descricao agora recebe \u0026#39;tipo\u0026#39; Esse tipo de bug é especialmente perigoso em código de backend onde data classes representam DTOs de APIs REST. A mudança silenciosa de semântica não gera erro de compilação — o tipo é compatível — mas corrompe dados em runtime.\nSe você já viu esse tipo de problema em projetos reais, sabe que é difícil de diagnosticar. Nosso guia sobre testes com JUnit5 e MockK ajuda a montar cenários que capturam regressões desse tipo, mas a solução definitiva é corrigir o mecanismo de linguagem.\nComo funciona a desestruturação por nome Com a flag do compilador habilitada, a desestruturação por nome resolve variáveis pelo nome da propriedade em vez da posição. A sintaxe usa parênteses com val explícito:\ndata class Transacao(val valor: Double, val tipo: String, val descricao: String) // Desestruturação por nome — ordem não importa val (val descricao, val valor) = transacao // descricao = transacao.descricao (correto!) // valor = transacao.valor (correto!) O compilador faz o match entre o nome da variável e o nome da propriedade. A ordem na declaração não importa mais. Isso elimina toda a classe de bugs descrita acima.\nRenomeando variáveis Quando você precisa usar um nome diferente da propriedade, a sintaxe suporta aliases:\nval (val desc = descricao, val amount = valor) = transacao // desc recebe transacao.descricao // amount recebe transacao.valor Isso é útil quando o nome da propriedade não é ideal para o contexto local ou quando há conflito de nomes com variáveis existentes no escopo.\nNova sintaxe de colchetes para posição A proposta também introduz colchetes para desestruturação posicional explícita. Isso é importante para tipos onde a ordem dos elementos é o que importa, como Pair, Triple, listas e mapas:\n// Posicional com colchetes — para Pair, Triple, etc. val [primeiro, segundo] = Pair(\u0026#34;Kotlin\u0026#34;, \u0026#34;Java\u0026#34;) // Em loops de Map for ([chave, valor] in mapaDeCidades) { println(\u0026#34;$chave -\u0026gt; $valor\u0026#34;) } A distinção visual entre parênteses (nome) e colchetes (posição) torna o código auto-documentado. Quem lê sabe imediatamente qual estratégia está sendo usada.\nComparação direta data class Config(val host: String, val port: Int, val debug: Boolean) val config = Config(\u0026#34;localhost\u0026#34;, 8080, true) // Por NOME — match por propriedade (nova sintaxe) val (val debug, val host) = config // debug = true, host = \u0026#34;localhost\u0026#34; // Por POSIÇÃO — match por componente (colchetes) val [primeiro, segundo] = config // primeiro = \u0026#34;localhost\u0026#34;, segundo = 8080 Habilitando no seu projeto Para usar a desestruturação por nome no Kotlin 2.3.20+, adicione a flag do compilador no Gradle:\n// build.gradle.kts kotlin { compilerOptions { freeCompilerArgs.add(\u0026#34;-Xname-based-destructuring=only-syntax\u0026#34;) } } A flag aceita três modos progressivos:\nModo Comportamento only-syntax Habilita a sintaxe val (val x, val y) sem alterar código existente name-mismatch Emite warnings quando nomes de variáveis não correspondem aos da data class complete Ativa o modo completo com parênteses para nome e colchetes para posição Para projetos existentes, comece com only-syntax para experimentar sem risco. Depois evolua para name-mismatch para identificar desestruturações potencialmente incorretas no código atual.\nExemplos práticos em cenários reais DTO de API com Spring Boot data class PedidoDTO( val id: Long, val cliente: String, val itens: List\u0026lt;ItemDTO\u0026gt;, val valorTotal: Double, val status: String ) fun processarPedido(dto: PedidoDTO) { // Por nome — extraímos apenas o que precisamos, na ordem que queremos val (val status, val valorTotal, val cliente) = dto when (status) { \u0026#34;PENDENTE\u0026#34; -\u0026gt; enviarNotificacao(cliente, valorTotal) \u0026#34;PAGO\u0026#34; -\u0026gt; iniciarEntrega(dto) \u0026#34;CANCELADO\u0026#34; -\u0026gt; estornar(cliente, valorTotal) } } A vantagem aqui é clara: se alguém adicionar uma nova propriedade ao PedidoDTO amanhã, o código de desestruturação continua funcionando corretamente. Isso é especialmente relevante em projetos de microserviços com Kotlin onde múltiplos times evoluem DTOs compartilhados.\nDesestruturação em lambdas A nova sintaxe funciona dentro de lambdas, o que é útil com collections e Flow:\ndata class Metrica(val nome: String, val valor: Double, val unidade: String) val metricas = listOf( Metrica(\u0026#34;cpu_usage\u0026#34;, 75.3, \u0026#34;%\u0026#34;), Metrica(\u0026#34;memory_mb\u0026#34;, 2048.0, \u0026#34;MB\u0026#34;), Metrica(\u0026#34;requests_per_sec\u0026#34;, 1200.0, \u0026#34;req/s\u0026#34;) ) // Desestruturação por nome na lambda metricas .filter { (val valor) -\u0026gt; valor \u0026gt; 100 } .forEach { (val nome, val valor, val unidade) -\u0026gt; println(\u0026#34;Alerta: $nome = $valor$unidade\u0026#34;) } Combinando com sealed classes sealed class Resultado { data class Sucesso(val dados: String, val timestamp: Long) : Resultado() data class Erro(val mensagem: String, val codigo: Int) : Resultado() } fun tratarResultado(resultado: Resultado) { when (resultado) { is Resultado.Sucesso -\u0026gt; { val (val dados, val timestamp) = resultado salvarCache(dados, timestamp) } is Resultado.Erro -\u0026gt; { val (val codigo, val mensagem) = resultado log.error(\u0026#34;Erro $codigo: $mensagem\u0026#34;) } } } Com sealed classes, a desestruturação por nome torna o pattern matching mais legível. A ordem dos campos na declaração reflete a importância semântica no contexto, não a posição na data class.\nFunciona com classes normais? Sim, desde que a classe exponha propriedades públicas. A desestruturação por nome não depende de componentN():\nclass Configuracao( val ambiente: String, val versao: String, val porta: Int ) { val urlCompleta: String get() = \u0026#34;$ambiente:$porta/v$versao\u0026#34; } val (val ambiente, val porta) = Configuracao(\u0026#34;prod\u0026#34;, \u0026#34;2.0\u0026#34;, 443) // ambiente = \u0026#34;prod\u0026#34;, porta = 443 Isso abre possibilidades para classes que antes não suportavam desestruturação sem implementar operator fun componentN() manualmente. Para quem trabalha com extension functions, isso significa que a desestruturação agora funciona com qualquer classe que tenha propriedades públicas.\nPlano de migração da JetBrains A KEEP-0438 define um plano de migração em três fases:\nFase 1 (atual): a nova sintaxe coexiste com a antiga. Parênteses sem val continuam sendo posicionais. A flag only-syntax permite usar a nova sintaxe sem efeitos colaterais.\nFase 2: o compilador emite warnings para desestruturações posicionais onde os nomes das variáveis não correspondem às propriedades. Isso ajuda a identificar código potencialmente incorreto.\nFase 3 (futuro): val (x, y) = e passa a significar desestruturação por nome por padrão. A desestruturação posicional migra para a sintaxe de colchetes [x, y].\nPara projetos que usam version catalogs no Gradle, a recomendação é fixar a flag do compilador no catálogo centralizado para garantir consistência entre módulos.\nImpacto na compatibilidade binária Um benefício menos óbvio da desestruturação por nome é a estabilidade da API binária. Com a abordagem posicional, adicionar uma propriedade no meio de uma data class quebra código que faz desestruturação. Com a abordagem por nome, a adição de novos campos não afeta código existente — apenas os campos explicitamente nomeados são extraídos.\nIsso é particularmente importante para autores de bibliotecas. Se você mantém uma lib Kotlin publicada no Maven Central, a desestruturação por nome permite evoluir data classes sem quebrar a compatibilidade com consumidores. Para quem trabalha com serialização avançada, essa estabilidade complementa o versionamento de schemas.\nConclusão A desestruturação por nome resolve um problema real que existia desde o Kotlin 1.0. A dependência da posição sempre foi uma fonte de bugs silenciosos, especialmente em equipes grandes onde data classes evoluem com frequência.\nA recomendação prática: habilite only-syntax no seu projeto hoje para experimentar. Depois migre para name-mismatch para encontrar desestruturações suspeitas no código existente. Quando a Fase 3 chegar em uma release futura, seu código já estará preparado.\nSe você está acompanhando as novidades do Kotlin em 2026, esse recurso se encaixa na mesma filosofia de segurança de tipo que motivou null safety, value classes e explicit backing fields. O Kotlin continua priorizando código correto por construção. Em outras linguagens do ecossistema de sistemas, Rust resolve desestruturação de structs por nome desde sua primeira versão estável, e a inspiração é clara na proposta da KEEP-0438. Linguagens como Python com seu unpacking e Go com acesso explícito a campos de structs adotam abordagens diferentes, mas o objetivo é o mesmo: evitar erros de posição.\nPara ver como os novos componentes de layout do Compose se beneficiam de data classes com desestruturação segura, confira nosso artigo sobre Grid, FlexBox e Media Query no Compose.\nPerguntas frequentes A desestruturação por nome funciona com Pair e Triple? Pair e Triple continuam usando desestruturação posicional com a nova sintaxe de colchetes: val [primeiro, segundo] = pair. Como esses tipos representam tuplas genéricas sem nomes semânticos, a abordagem posicional com colchetes é a mais adequada.\nPreciso reescrever todo meu código existente? Nao. O modo only-syntax permite adotar a nova sintaxe gradualmente em código novo sem afetar código existente. A migração completa para a Fase 3 acontecerá em uma release futura com período de deprecação e ferramentas automáticas de migração no IntelliJ IDEA.\nA desestruturação por nome é mais lenta que a posicional? Nao. Ambas as formas geram o mesmo bytecode no JVM. A resolução por nome acontece em tempo de compilação — o compilador traduz val (val nome) = pessoa para val nome = pessoa.nome, sem overhead em runtime.\nPosso misturar desestruturação por nome e por posição no mesmo arquivo? Sim. Com a flag only-syntax, parênteses sem val continuam sendo posicionais e parênteses com val são por nome. Isso permite migração gradual dentro do mesmo arquivo ou módulo.\n","permalink":"https://kotlin.dev.br/blog/kotlin-name-based-destructuring-2026/","summary":"\u003cp\u003eA desestruturação é um dos recursos mais usados no Kotlin. Toda vez que você escreve \u003ccode\u003eval (nome, idade) = pessoa\u003c/code\u003e, está usando esse mecanismo. O problema é que, até agora, a desestruturação dependia exclusivamente da \u003cstrong\u003eposição\u003c/strong\u003e dos componentes — e isso gerava bugs sutis que só apareciam em produção.\u003c/p\u003e\n\u003cp\u003eA partir do \u003cstrong\u003eKotlin 2.3.20\u003c/strong\u003e, o compilador introduziu a \u003cstrong\u003edesestruturação por nome\u003c/strong\u003e (name-based destructuring) como recurso experimental. A proposta KEEP-0438 define uma mudança fundamental na forma como o Kotlin resolve variáveis em declarações de desestruturação, trazendo segurança semântica sem sacrificar a ergonomia da linguagem.\u003c/p\u003e","title":"Kotlin Name-Based Destructuring: Guia Completo"},{"content":"A release de abril de 2026 do Jetpack Compose trouxe algo que muitos desenvolvedores Android e multiplataforma pediam havia tempo: componentes de layout de verdade para interfaces adaptativas. Grid, FlexBox e Media Query API chegaram como APIs experimentais e prometem mudar a forma como construímos telas responsivas em Kotlin.\nSe você trabalha com Jetpack Compose no dia a dia, sabe que montar layouts complexos com Row e Column aninhados rapidamente vira uma dor de cabeça. Breakpoints manuais, cálculos de largura e lógica condicional espalhada por todo o Composable tornam o código difícil de manter. Os três novos componentes resolvem exatamente isso.\nNeste artigo, vamos explorar cada API com exemplos práticos e prontos para copiar.\nO que mudou no Compose em abril de 2026? A atualização trouxe três APIs experimentais que seguem padrões já consolidados no desenvolvimento web:\nGrid: layout bidimensional com linhas, colunas e spans FlexBox: distribuição flexível de itens com wrap e alinhamento em múltiplos eixos Media Query API: adaptação declarativa baseada em sinais do ambiente como tamanho de janela, postura do dispositivo e tipo de input Além dessas, a release também incluiu uma nova Styles API para estilização baseada em estado e melhorias no suporte a trackpad. Mas o foco deste artigo são os três componentes de layout, que impactam diretamente a arquitetura de qualquer app adaptativo.\nSe você já trabalha com Compose Multiplatform, essas APIs funcionam também no Desktop e Web, tornando ainda mais viável compartilhar código de UI entre plataformas.\nGrid: layouts bidimensionais de verdade O componente Grid resolve o problema mais comum de quem precisa montar dashboards, galerias ou qualquer tela com disposição em grade. Antes, era preciso combinar LazyVerticalGrid com cálculos manuais. Agora, a API oferece controle total sobre tracks (linhas e colunas), gaps e spans.\nExemplo básico: grade de cards @OptIn(ExperimentalComposeApi::class) @Composable fun DashboardGrid() { Grid( config = { columns(4) { fraction(0.25f) } rows(2) { fraction(0.5f) } gap(16.dp) } ) { MetricCard( titulo = \u0026#34;Receita\u0026#34;, valor = \u0026#34;R$ 42.500\u0026#34;, modifier = Modifier.gridItem(rowSpan = 2) ) MetricCard( titulo = \u0026#34;Usuarios\u0026#34;, valor = \u0026#34;1.230\u0026#34;, modifier = Modifier.gridItem(columnSpan = 2) ) MetricCard(titulo = \u0026#34;Pedidos\u0026#34;, valor = \u0026#34;89\u0026#34;) MetricCard(titulo = \u0026#34;Conversao\u0026#34;, valor = \u0026#34;3,2%\u0026#34;) } } O Grid aceita diferentes unidades de dimensionamento: Dp fixo, frações (Fr), porcentagens e até tamanhos intrínsecos baseados no conteúdo. Isso permite criar grades que se adaptam naturalmente ao espaço disponível sem cálculos manuais.\nExemplo avançado: adaptação por orientação @OptIn(ExperimentalComposeApi::class) @Composable fun AdaptiveProductGrid(produtos: List\u0026lt;Produto\u0026gt;) { val configuration = LocalConfiguration.current val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE Grid( config = { if (isLandscape) { columns(4) { fraction(0.25f) } } else { columns(2) { fraction(0.5f) } } row { auto() } gap(horizontal = 12.dp, vertical = 16.dp) } ) { produtos.forEach { produto -\u0026gt; ProductCard( produto = produto, modifier = if (produto.destaque) { Modifier.gridItem(columnSpan = 2) } else { Modifier } ) } } } Quem já construiu telas com layouts em Compose vai perceber que o Grid elimina boa parte da lógica condicional que antes era necessária para responsividade.\nFlexBox: distribuição inteligente de itens O FlexBox segue a mesma filosofia do CSS Flexbox: distribuir itens dentro de um container com controle sobre direção, wrap, alinhamento e proporção. A grande vantagem sobre Row e Column é o suporte nativo a wrap — quando os itens não cabem em uma linha, eles quebram automaticamente para a próxima.\nExemplo: barra de tags com wrap @OptIn(ExperimentalComposeApi::class) @Composable fun TagBar(tags: List\u0026lt;String\u0026gt;) { FlexBox( config = { wrap(FlexWrap.Wrap) gap(8.dp) justifyContent(JustifyContent.Start) alignItems(AlignItems.Center) } ) { tags.forEach { tag -\u0026gt; TagChip( text = tag, modifier = Modifier.flex { shrink(0f) } ) } } } @Composable fun TagChip(text: String, modifier: Modifier = Modifier) { Surface( modifier = modifier, shape = RoundedCornerShape(16.dp), color = MaterialTheme.colorScheme.secondaryContainer ) { Text( text = text, modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp), style = MaterialTheme.typography.labelMedium ) } } Exemplo: layout de formulário adaptativo @OptIn(ExperimentalComposeApi::class) @Composable fun AdaptiveForm() { FlexBox( config = { wrap(FlexWrap.Wrap) gap(horizontal = 16.dp, vertical = 12.dp) } ) { OutlinedTextField( value = \u0026#34;\u0026#34;, onValueChange = {}, label = { Text(\u0026#34;Nome\u0026#34;) }, modifier = Modifier.flex { grow(1f) basis(200.dp) } ) OutlinedTextField( value = \u0026#34;\u0026#34;, onValueChange = {}, label = { Text(\u0026#34;Email\u0026#34;) }, modifier = Modifier.flex { grow(2f) basis(300.dp) } ) OutlinedTextField( value = \u0026#34;\u0026#34;, onValueChange = {}, label = { Text(\u0026#34;Telefone\u0026#34;) }, modifier = Modifier.flex { grow(1f) basis(150.dp) } ) } } O basis define o tamanho mínimo preferido antes da distribuição do espaço extra via grow. Isso garante que os campos nunca fiquem menores do que o necessário, mas expandem proporcionalmente quando há espaço sobrando. Para quem já usou Kotlin DSL em outros contextos, a API do FlexBox segue o mesmo padrão de configuração declarativa.\nMedia Query API: adaptação baseada no ambiente A Media Query API é possivelmente a adição mais poderosa desta release. Ela permite que seu Composable reaja declarativamente a sinais do ambiente sem precisar de lógica imperativa espalhada pelo código.\nSinais disponíveis A API reconhece diversos sinais ambientais:\nTamanho da janela: largura e altura em WindowSizeClass (compact, medium, expanded) Postura do dispositivo: flat, half-opened, tabletop (para dobráveis) Tipo de teclado: virtual ou físico Precisão do ponteiro: touch ou mouse Orientação: portrait ou landscape Exemplo: layout responsivo com Media Query @OptIn(ExperimentalComposeApi::class) @Composable fun ResponsiveHomeScreen(viewModel: HomeViewModel) { val showSidebar = mediaQuery { windowWidthSizeClass \u0026gt;= WindowWidthSizeClass.Medium } val isTabletop = mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } if (isTabletop) { TabletopLayout(viewModel) } else if (showSidebar) { Row { NavigationSidebar(modifier = Modifier.width(280.dp)) MainContent( viewModel = viewModel, modifier = Modifier.weight(1f) ) } } else { Column { MainContent( viewModel = viewModel, modifier = Modifier.weight(1f) ) BottomNavigation() } } } Performance com derivedMediaQuery Para sinais que mudam com alta frequência, a API oferece derivedMediaQuery, que otimiza recomposições usando derivedStateOf internamente:\n@OptIn(ExperimentalComposeApi::class) @Composable fun AdaptiveGrid(items: List\u0026lt;Item\u0026gt;) { val columnCount = derivedMediaQuery { when { windowWidthSizeClass == WindowWidthSizeClass.Expanded -\u0026gt; 4 windowWidthSizeClass == WindowWidthSizeClass.Medium -\u0026gt; 3 else -\u0026gt; 2 } } Grid( config = { columns(columnCount) { fraction(1f / columnCount) } gap(12.dp) } ) { items.forEach { item -\u0026gt; ItemCard(item) } } } Essa composição entre Grid e Media Query API mostra o verdadeiro poder das novas APIs trabalhando juntas. Se você já lida com observabilidade em apps Kotlin, vale monitorar o impacto de recomposições usando essas ferramentas.\nCombinando Grid, FlexBox e Media Query Na prática, as três APIs se complementam. Um cenário comum seria:\n@OptIn(ExperimentalComposeApi::class) @Composable fun ProductCatalogScreen(produtos: List\u0026lt;Produto\u0026gt;, categorias: List\u0026lt;String\u0026gt;) { val isExpanded = mediaQuery { windowWidthSizeClass == WindowWidthSizeClass.Expanded } Column(modifier = Modifier.fillMaxSize().padding(16.dp)) { // Tags de filtro com wrap automático FlexBox( config = { wrap(FlexWrap.Wrap) gap(8.dp) } ) { categorias.forEach { cat -\u0026gt; FilterChip(selected = false, onClick = {}, label = { Text(cat) }) } } Spacer(modifier = Modifier.height(16.dp)) // Grade adaptativa de produtos Grid( config = { if (isExpanded) { columns(4) { fraction(0.25f) } } else { columns(2) { fraction(0.5f) } } gap(12.dp) } ) { produtos.forEach { produto -\u0026gt; ProductCard(produto) } } } } Como habilitar as novas APIs Todas as APIs desta release são experimentais. Para usá-las, adicione a dependência mais recente do Compose BOM e a anotação @OptIn:\n// build.gradle.kts dependencies { implementation(platform(\u0026#34;androidx.compose:compose-bom:2026.04.00\u0026#34;)) implementation(\u0026#34;androidx.compose.foundation:foundation\u0026#34;) implementation(\u0026#34;androidx.compose.foundation:foundation-layout\u0026#34;) } No código, use @OptIn(ExperimentalComposeApi::class) em cada Composable que utilize Grid, FlexBox ou Media Query.\nSe você está configurando um projeto do zero, nosso tutorial de Compose com Android Studio cobre o setup inicial completo. Para projetos multiplataforma, o guia de Compose Multiplatform Desktop mostra como compartilhar código de UI entre Android e Desktop.\nQuando usar cada componente Cenário Componente Dashboard com cards em grade Grid Barra de tags ou chips com quebra de linha FlexBox Formulário com campos de tamanho variável FlexBox Layout completamente diferente por tamanho de tela Media Query Galeria de imagens com itens em destaque Grid + Media Query Adaptação para dispositivos dobráveis Media Query Conclusão Grid, FlexBox e Media Query API representam a maior evolução de layout do Jetpack Compose desde o lançamento do framework. Juntas, elas eliminam a necessidade de gambiarras com Row/Column aninhados e lógica condicional espalhada pelo código.\nSe você já domina os fundamentos do Compose, é hora de experimentar essas APIs em protótipos. Elas ainda são experimentais, mas a direção é clara: o Compose está se tornando um framework de layout tão poderoso quanto CSS Grid e Flexbox na web, com a vantagem de tipagem estática e integração nativa com o ecossistema Kotlin.\nPara quem trabalha com Kotlin Multiplatform, a boa notícia é que essas APIs fazem parte do Compose Foundation, disponível para Android, Desktop e Web. Combine isso com Navigation 3 e Hot Reload e você tem um toolkit completo para aplicações modernas. No ecossistema web, Go tem explorado abordagens como HTMX para UIs reativas no servidor, mas o Compose oferece uma experiência declarativa nativa que dispensa JavaScript no client. Linguagens como Rust com egui também investem em UI declarativa, mostrando que esse paradigma está se consolidando além do ecossistema Android.\nSe você está migrando de XML para Compose, nosso guia de Jetpack Compose completo cobre a transição passo a passo. E para entender como a nova desestruturação por nome do Kotlin pode simplificar seu código de UI com data classes, confira o artigo complementar.\nPerguntas frequentes O Grid do Compose substitui LazyVerticalGrid? Não diretamente. O Grid é voltado para layouts fixos e responsivos com controle de tracks e spans. O LazyVerticalGrid continua sendo a melhor opção para listas longas com reciclagem de itens. Use Grid para dashboards e layouts de página, e LazyVerticalGrid para feeds e catálogos com scroll infinito.\nFlexBox funciona em Compose Multiplatform? Sim. O FlexBox faz parte do foundation-layout, que está disponível em todas as plataformas suportadas pelo Compose Multiplatform: Android, Desktop (JVM), iOS e Web (via Kotlin/Wasm). A API é a mesma em todas as plataformas.\nA Media Query API recompoe muito e prejudica performance? A API foi projetada com otimização em mente. Ela usa derivedStateOf internamente para sinais de alta frequência, e o derivedMediaQuery permite controle fino sobre quando recomposições acontecem. Na prática, a performance é comparável a verificar LocalConfiguration.current manualmente.\nPreciso de alguma versão mínima do Android para usar Grid e FlexBox? As APIs experimentais do Compose seguem o suporte padrão do Compose Foundation, que funciona a partir do Android API 21 (Lollipop). A Media Query API para detecção de postura em dobráveis requer a biblioteca WindowManager da Jetpack e dispositivos compatíveis.\n","permalink":"https://kotlin.dev.br/blog/jetpack-compose-grid-flexbox-media-query-2026/","summary":"\u003cp\u003eA release de abril de 2026 do Jetpack Compose trouxe algo que muitos desenvolvedores Android e multiplataforma pediam havia tempo: \u003cstrong\u003ecomponentes de layout de verdade para interfaces adaptativas\u003c/strong\u003e. Grid, FlexBox e Media Query API chegaram como APIs experimentais e prometem mudar a forma como construímos telas responsivas em Kotlin.\u003c/p\u003e\n\u003cp\u003eSe você trabalha com \u003ca href=\"/tutoriais/jetpack-compose-basico/\"\u003eJetpack Compose\u003c/a\u003e no dia a dia, sabe que montar layouts complexos com \u003ccode\u003eRow\u003c/code\u003e e \u003ccode\u003eColumn\u003c/code\u003e aninhados rapidamente vira uma dor de cabeça. Breakpoints manuais, cálculos de largura e lógica condicional espalhada por todo o Composable tornam o código difícil de manter. Os três novos componentes resolvem exatamente isso.\u003c/p\u003e","title":"Compose Grid, FlexBox e Media Query: Guia Prático"},{"content":"O Compose Multiplatform (CMP) evoluiu de forma significativa nos ultimos dois anos. Em 2026, a camada iOS saiu de alpha para beta estavel e ja sustenta aplicacoes em producao em empresas como Philips, Cash App e diversas startups brasileiras. Se voce acompanhou as novidades do Compose Multiplatform 1.10.6 ou ja usa CMP para desktop, este artigo mostra o que mudou para iOS e como levar seu projeto para producao com confianca.\nEstado atual do Compose Multiplatform para iOS A JetBrains declarou a camada iOS como Beta a partir da versao 1.7 e, desde entao, cada release trouxe ganhos de estabilidade e performance. O motor de renderizacao usa Skia via Skiko, o que significa que os composables sao desenhados pixel a pixel — sem depender de widgets nativos do UIKit.\nNa pratica, isso traz duas consequencias:\nConsistencia visual entre Android e iOS sem esforco adicional. Necessidade de interop quando voce precisa de componentes nativos como mapas, cameras ou web views. O ecossistema Kotlin Multiplatform fornece a base de compartilhamento de logica, enquanto o CMP cuida exclusivamente da camada de UI. Juntos, eles permitem compartilhar ate 90% do codigo entre plataformas.\nInterop com UIKit usando UIKitView Para componentes que exigem renderizacao nativa, o CMP oferece o composable UIKitView. Ele permite incorporar qualquer UIView dentro de uma arvore Compose:\nimport androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.interop.UIKitView import platform.MapKit.MKMapView @Composable fun NativeMapView(modifier: Modifier = Modifier) { UIKitView( factory = { MKMapView() }, modifier = modifier, update = { mapView -\u0026gt; mapView.showsUserLocation = true mapView.mapType = platform.MapKit.MKMapType.MKMapTypeStandard } ) } O parametro factory cria a view nativa uma unica vez, enquanto update e chamado a cada recomposicao. Esse padrao e identico ao AndroidView no Jetpack Compose, o que facilita a transicao para quem ja desenvolve para Android.\nInterop com SwiftUI Alem do UIKit, o CMP suporta interop com SwiftUI por meio de UIKitViewController combinado com UIHostingController. Esse caminho e util quando voce quer reutilizar componentes SwiftUI existentes:\nimport androidx.compose.runtime.Composable import androidx.compose.ui.interop.UIKitViewController import platform.UIKit.UIViewController @Composable fun SwiftUIBridge( factory: () -\u0026gt; UIViewController ) { UIKitViewController( factory = factory, modifier = androidx.compose.ui.Modifier.fillMaxSize() ) } No lado Swift, voce cria o UIHostingController com a view desejada e passa como factory. Essa abordagem permite adotar CMP gradualmente, tela por tela, sem reescrever componentes SwiftUI que ja funcionam. Se voce esta avaliando a comparacao entre Kotlin e Swift para mobile, essa flexibilidade e um diferencial importante.\nExpect/Actual para codigo especifico de plataforma O mecanismo expect/actual do Kotlin Multiplatform e essencial para abstrair diferencas entre plataformas. Veja como definir um componente de status bar que se comporta de forma diferente em cada SO:\n// commonMain expect fun configurePlatformStatusBar(isDark: Boolean) // androidMain actual fun configurePlatformStatusBar(isDark: Boolean) { val window = currentActivity.window WindowCompat.getInsetsController(window, window.decorView) .isAppearanceLightStatusBars = !isDark } // iosMain actual fun configurePlatformStatusBar(isDark: Boolean) { UIApplication.sharedApplication.setStatusBarStyle( if (isDark) UIStatusBarStyleLightContent else UIStatusBarStyleDarkContent, animated = true ) } Esse padrao se aplica a qualquer funcionalidade que varie entre plataformas: notificacoes, biometria, armazenamento seguro e permissoes. O compilador K2 garante em tempo de compilacao que toda declaracao expect tenha uma implementacao actual correspondente.\nPerformance: CMP vs SwiftUI nativo Um dos maiores questionamentos sobre CMP no iOS e a performance. Benchmarks recentes mostram que:\nMetrica CMP (iOS) SwiftUI nativo Tempo de inicializacao ~320ms ~180ms Scroll de lista (1000 itens) 58-60 fps 60 fps Consumo de memoria (tela complexa) ~45 MB ~38 MB Tamanho do binario (app minimo) ~18 MB ~8 MB O overhead de inicializacao vem do bootstrap do runtime Kotlin/Native e do Skia. Apos o start, a diferenca de performance e imperceptivel para o usuario. O tamanho do binario e maior por incluir o Skiko, mas tecnicas como strip de simbolos e link-time optimization reduzem esse impacto.\nPara projetos onde a performance e critica, o profiling com Instruments da Apple funciona normalmente com binarios CMP. Alem disso, o suporte a Swift Package Manager no KMP simplifica a integracao com o toolchain iOS.\nEstrategias de navegacao A navegacao em projetos CMP para iOS segue dois caminhos principais:\nNavegacao compartilhada com bibliotecas como Voyager ou Decompose, onde toda a logica de navegacao vive no commonMain. Navegacao nativa usando UINavigationController no iOS e Navigation Compose no Android, conectando via expect/actual. A primeira abordagem maximiza o compartilhamento de codigo. A segunda oferece transicoes e gestos nativos (como o swipe-back do iOS). A escolha depende do quanto de UX nativa voce precisa preservar.\nPara persistencia de dados local em ambas as plataformas, o Room com KMP e uma opcao madura que funciona tanto no Android quanto no iOS.\nQuando escolher CMP para iOS O Compose Multiplatform para iOS faz sentido quando:\nVoce ja tem uma equipe forte em Kotlin e nao quer manter dois codebases separados. A consistencia visual entre plataformas e mais importante que seguir pixel a pixel as guidelines do iOS. O projeto precisa de iteracao rapida e voce quer uma unica fonte de verdade para a UI. Por outro lado, se o app exige integracao profunda com APIs exclusivas do iOS (HealthKit, ARKit, CarPlay), a camada nativa pode ser mais produtiva. A boa noticia e que o interop com UIKit e SwiftUI permite uma abordagem hibrida.\nDesenvolvedores que vem de outras linguagens tambem encontram paralelos uteis. Em Go, o compartilhamento de codigo entre plataformas exige CGO e wrappers manuais. Em Python, frameworks como Kivy existem, mas nao oferecem a mesma integracao nativa. Ja em Rust, projetos como Slint avancam no cross-platform, mas a maturidade do ecossistema mobile ainda esta atras do CMP.\nConclusao O Compose Multiplatform para iOS em 2026 e uma opcao viavel para producao. A combinacao de renderizacao Skia, interop flexivel com UIKit/SwiftUI e o mecanismo expect/actual cria um ambiente produtivo para equipes que querem maximizar o compartilhamento de codigo sem sacrificar a experiencia do usuario. Se voce ja usa KMP para logica de negocio, adicionar CMP para a camada de UI e o proximo passo natural.\nPerguntas frequentes O Compose Multiplatform para iOS esta pronto para producao? Sim, em 2026 a camada iOS esta em Beta estavel e empresas como Philips e Cash App ja utilizam em producao. A JetBrains oferece suporte ativo e cada release traz melhorias de estabilidade e performance.\nQual a diferenca de performance entre CMP e SwiftUI nativo? Apos a inicializacao, a diferenca e minima. O scroll de listas complexas roda a 58-60 fps em CMP contra 60 fps em SwiftUI. O maior impacto esta no tamanho do binario (~18 MB vs ~8 MB) e no tempo de cold start (~320ms vs ~180ms).\nPosso usar componentes nativos do iOS dentro do Compose Multiplatform? Sim, o composable UIKitView permite incorporar qualquer UIView nativa dentro da arvore Compose. Para componentes SwiftUI, voce pode usar UIKitViewController com UIHostingController como ponte.\nPreciso reescrever todo o app para usar CMP no iOS? Nao. O CMP suporta adocao gradual. Voce pode comecar com uma unica tela compartilhada e manter o restante do app em SwiftUI ou UIKit, expandindo o uso conforme ganhar confianca na ferramenta.\n","permalink":"https://kotlin.dev.br/blog/compose-multiplatform-ios-producao-2026/","summary":"\u003cp\u003eO Compose Multiplatform (CMP) evoluiu de forma significativa nos ultimos dois anos. Em 2026, a camada iOS saiu de alpha para beta estavel e ja sustenta aplicacoes em producao em empresas como Philips, Cash App e diversas startups brasileiras. Se voce acompanhou as \u003ca href=\"/blog/compose-multiplatform-1-10-6-2026/\"\u003enovidades do Compose Multiplatform 1.10.6\u003c/a\u003e ou ja usa \u003ca href=\"/blog/kotlin-compose-multiplatform-desktop/\"\u003eCMP para desktop\u003c/a\u003e, este artigo mostra o que mudou para iOS e como levar seu projeto para producao com confianca.\u003c/p\u003e\n\u003ch2 id=\"estado-atual-do-compose-multiplatform-para-ios\"\u003eEstado atual do Compose Multiplatform para iOS\u003c/h2\u003e\n\u003cp\u003eA JetBrains declarou a camada iOS como \u003cstrong\u003eBeta\u003c/strong\u003e a partir da versao 1.7 e, desde entao, cada release trouxe ganhos de estabilidade e performance. O motor de renderizacao usa Skia via Skiko, o que significa que os composables sao desenhados pixel a pixel — sem depender de widgets nativos do UIKit.\u003c/p\u003e","title":"Compose Multiplatform para iOS em Produção: Guia 2026"},{"content":"A kotlinx.serialization é a biblioteca oficial do Kotlin para serialização e desserialização de dados, e vai muito além do básico @Serializable em data classes. Quando você trabalha com APIs que retornam tipos variados, precisa lidar com formatos legados ou quer otimizar payloads, os recursos avançados da biblioteca fazem toda a diferença.\nNeste artigo, vamos explorar polimorfismo com sealed classes, serializers customizados, serialização contextual e padrões avançados que resolvem problemas reais em projetos Kotlin. Se você já domina o básico, este guia vai elevar seu nível.\nPolimorfismo com sealed classes O cenário mais comum de serialização polimórfica acontece quando uma API retorna diferentes tipos de objetos em uma mesma lista ou campo. Considere um sistema de notificações:\nimport kotlinx.serialization.* import kotlinx.serialization.json.* @Serializable sealed class Notificacao { abstract val id: String abstract val timestamp: Long @Serializable @SerialName(\u0026#34;email\u0026#34;) data class Email( override val id: String, override val timestamp: Long, val destinatario: String, val assunto: String, val corpo: String ) : Notificacao() @Serializable @SerialName(\u0026#34;push\u0026#34;) data class Push( override val id: String, override val timestamp: Long, val titulo: String, val mensagem: String, val icone: String? = null ) : Notificacao() @Serializable @SerialName(\u0026#34;sms\u0026#34;) data class Sms( override val id: String, override val timestamp: Long, val telefone: String, val texto: String ) : Notificacao() } Com sealed classes, o compilador conhece todos os subtipos em tempo de compilação, e a serialização funciona automaticamente:\nval json = Json { prettyPrint = true } val notificacoes: List\u0026lt;Notificacao\u0026gt; = listOf( Notificacao.Email( id = \u0026#34;1\u0026#34;, timestamp = System.currentTimeMillis(), destinatario = \u0026#34;dev@kotlin.dev.br\u0026#34;, assunto = \u0026#34;Deploy concluído\u0026#34;, corpo = \u0026#34;O deploy da v2.5 foi finalizado com sucesso.\u0026#34; ), Notificacao.Push( id = \u0026#34;2\u0026#34;, timestamp = System.currentTimeMillis(), titulo = \u0026#34;Nova versão\u0026#34;, mensagem = \u0026#34;Kotlin 2.4.0 disponível!\u0026#34; ) ) val texto = json.encodeToString(notificacoes) println(texto) O JSON gerado inclui automaticamente o campo discriminador type:\n[ { \u0026#34;type\u0026#34;: \u0026#34;email\u0026#34;, \u0026#34;id\u0026#34;: \u0026#34;1\u0026#34;, \u0026#34;timestamp\u0026#34;: 1745856000000, \u0026#34;destinatario\u0026#34;: \u0026#34;dev@kotlin.dev.br\u0026#34;, \u0026#34;assunto\u0026#34;: \u0026#34;Deploy concluído\u0026#34;, \u0026#34;corpo\u0026#34;: \u0026#34;O deploy da v2.5 foi finalizado com sucesso.\u0026#34; }, { \u0026#34;type\u0026#34;: \u0026#34;push\u0026#34;, \u0026#34;id\u0026#34;: \u0026#34;2\u0026#34;, \u0026#34;timestamp\u0026#34;: 1745856000000, \u0026#34;titulo\u0026#34;: \u0026#34;Nova versão\u0026#34;, \u0026#34;mensagem\u0026#34;: \u0026#34;Kotlin 2.4.0 disponível!\u0026#34; } ] O @SerialName define o valor do discriminador — sem ele, o nome completo da classe é usado, o que raramente é desejável em APIs públicas.\nSerializers customizados com KSerializer Quando o formato do JSON não corresponde à estrutura da sua classe Kotlin, você precisa de um serializer customizado. Um caso clássico: APIs que representam datas como strings em formato brasileiro:\nimport kotlinx.serialization.* import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.* import java.time.LocalDate import java.time.format.DateTimeFormatter object LocalDateBrSerializer : KSerializer\u0026lt;LocalDate\u0026gt; { private val formatter = DateTimeFormatter.ofPattern(\u0026#34;dd/MM/yyyy\u0026#34;) override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(\u0026#34;LocalDateBr\u0026#34;, PrimitiveKind.STRING) override fun serialize(encoder: Encoder, value: LocalDate) { encoder.encodeString(value.format(formatter)) } override fun deserialize(decoder: Decoder): LocalDate { return LocalDate.parse(decoder.decodeString(), formatter) } } @Serializable data class Evento( val nome: String, @Serializable(with = LocalDateBrSerializer::class) val data: LocalDate, val local: String ) Agora, ao serializar um Evento, a data aparece no formato 28/04/2026 em vez do ISO padrão. Esse padrão é especialmente útil para integrar com APIs legadas ou serviços que usam formatos não padronizados.\nJsonContentPolymorphicSerializer para APIs sem discriminador Nem toda API inclui um campo type para indicar o tipo do objeto. Muitas APIs retornam objetos onde o tipo é inferido pela presença ou ausência de campos específicos. O JsonContentPolymorphicSerializer resolve isso:\n@Serializable(with = PagamentoSerializer::class) sealed class Pagamento { abstract val valor: Double @Serializable data class CartaoCredito( override val valor: Double, val bandeira: String, val ultimos4Digitos: String, val parcelas: Int = 1 ) : Pagamento() @Serializable data class Pix( override val valor: Double, val chave: String, val txId: String ) : Pagamento() @Serializable data class Boleto( override val valor: Double, val codigoBarras: String, val vencimento: String ) : Pagamento() } object PagamentoSerializer : JsonContentPolymorphicSerializer\u0026lt;Pagamento\u0026gt;( Pagamento::class ) { override fun selectDeserializer( element: JsonElement ): DeserializationStrategy\u0026lt;Pagamento\u0026gt; { val jsonObject = element.jsonObject return when { \u0026#34;bandeira\u0026#34; in jsonObject -\u0026gt; Pagamento.CartaoCredito.serializer() \u0026#34;chave\u0026#34; in jsonObject -\u0026gt; Pagamento.Pix.serializer() \u0026#34;codigoBarras\u0026#34; in jsonObject -\u0026gt; Pagamento.Boleto.serializer() else -\u0026gt; throw SerializationException( \u0026#34;Tipo de pagamento desconhecido: ${jsonObject.keys}\u0026#34; ) } } } O serializer examina o conteúdo JSON para decidir qual tipo instanciar. Essa abordagem funciona perfeitamente com APIs de terceiros onde você não tem controle sobre o formato de resposta.\nSerialização contextual A serialização contextual permite registrar serializers em runtime, separando a lógica de serialização da definição da classe. Isso é útil quando uma mesma classe precisa ser serializada de formas diferentes dependendo do contexto:\nimport kotlinx.serialization.modules.* @Serializable data class Relatorio( val titulo: String, @Contextual val geradoEm: LocalDate, val dados: Map\u0026lt;String, Int\u0026gt; ) // Módulo para formato brasileiro val moduloBrasileiro = SerializersModule { contextual(LocalDateBrSerializer) } // Módulo para formato ISO val moduloISO = SerializersModule { contextual(LocalDateISOSerializer) } // JSON configurado para o contexto brasileiro val jsonBr = Json { serializersModule = moduloBrasileiro prettyPrint = true } // JSON configurado para APIs internacionais val jsonISO = Json { serializersModule = moduloISO } fun main() { val relatorio = Relatorio( titulo = \u0026#34;Vendas Q1\u0026#34;, geradoEm = LocalDate.of(2026, 4, 28), dados = mapOf(\u0026#34;janeiro\u0026#34; to 1500, \u0026#34;fevereiro\u0026#34; to 2300, \u0026#34;marco\u0026#34; to 1800) ) // Mesmo objeto, formatos diferentes println(jsonBr.encodeToString(relatorio)) // geradoEm: \u0026#34;28/04/2026\u0026#34; println(jsonISO.encodeToString(relatorio)) // geradoEm: \u0026#34;2026-04-28\u0026#34; } Esse padrão é poderoso em aplicações que servem múltiplos clientes — um frontend brasileiro pode receber datas em formato local, enquanto uma API parceira recebe no formato ISO.\nPolimorfismo aberto com SerializersModule Quando você não pode usar sealed classes (por exemplo, quando subtipos são definidos em módulos diferentes), o polimorfismo aberto com registro explícito é a solução:\n@Serializable abstract class Componente { abstract val id: String } // Módulo A @Serializable @SerialName(\u0026#34;botao\u0026#34;) data class Botao( override val id: String, val texto: String, val acao: String ) : Componente() // Módulo B @Serializable @SerialName(\u0026#34;campo_texto\u0026#34;) data class CampoTexto( override val id: String, val placeholder: String, val maxLength: Int = 255 ) : Componente() // Registro de todos os subtipos val componentesModule = SerializersModule { polymorphic(Componente::class) { subclass(Botao::class, Botao.serializer()) subclass(CampoTexto::class, CampoTexto.serializer()) } } val json = Json { serializersModule = componentesModule classDiscriminator = \u0026#34;componente_tipo\u0026#34; } Note o uso de classDiscriminator para customizar o nome do campo discriminador — útil quando o nome padrão type conflita com campos do seu modelo.\nTratamento de campos desconhecidos e defaults Em APIs reais, é comum receber campos que não existem no seu modelo ou lidar com campos opcionais. A configuração correta do Json evita crashes em produção:\nval jsonResilient = Json { // Ignora campos no JSON que não existem na classe ignoreUnknownKeys = true // Usa valores default para campos ausentes no JSON encodeDefaults = false // Permite valores nulos para campos não-nullable com default coerceInputValues = true // Aceita JSON malformado (aspas simples, trailing commas) isLenient = true } @Serializable data class UsuarioAPI( val id: Long, val nome: String, val email: String, val premium: Boolean = false, // Default se ausente val avatar: String? = null // Nullable com default ) Com ignoreUnknownKeys = true, o serializer não lança exceção quando a API adiciona novos campos que seu modelo ainda não contempla — essencial para manter compatibilidade com APIs que evoluem sem versionamento.\nPerformance e boas práticas Algumas dicas para otimizar a serialização em projetos de produção:\n// Crie uma única instância de Json e reutilize val appJson = Json { ignoreUnknownKeys = true encodeDefaults = false serializersModule = SerializersModule { contextual(LocalDateBrSerializer) polymorphic(Notificacao::class) { subclass(Notificacao.Email::class) subclass(Notificacao.Push::class) subclass(Notificacao.Sms::class) } } } // Evite criar instâncias de Json dentro de loops ou funções chamadas frequentemente // A instância de Json contém cache interno de serializers Se você usa Ktor para APIs, a kotlinx.serialization é a escolha nativa e se integra perfeitamente com o content negotiation. Para quem trabalha com Spring Boot e Kotlin, o suporte também funciona bem como alternativa ao Jackson.\nConclusão A kotlinx.serialization vai muito além do básico @Serializable. Com polimorfismo — via sealed classes ou registro aberto — serializers customizados e serialização contextual, você consegue modelar praticamente qualquer formato de dados que encontrar em produção.\nAs técnicas deste artigo são especialmente valiosas quando você integra com APIs externas que fogem dos padrões, trabalha com múltiplos formatos de saída ou precisa de performance otimizada. Se você usa coroutines e Flow para consumir dados reativamente, a serialização eficiente é peça fundamental do pipeline.\nOutra linguagem que se destaca em serialização type-safe é Rust com serde — vale comparar as abordagens se você trabalha com múltiplas linguagens. Para quem vem de Python, a kotlinx.serialization oferece segurança de tipos em tempo de compilação que Pydantic e dataclasses só validam em runtime.\n","permalink":"https://kotlin.dev.br/blog/kotlin-serialization-avancada-polimorfismo-2026/","summary":"\u003cp\u003eA \u003ccode\u003ekotlinx.serialization\u003c/code\u003e é a biblioteca oficial do Kotlin para serialização e desserialização de dados, e vai muito além do básico \u003ccode\u003e@Serializable\u003c/code\u003e em data classes. Quando você trabalha com APIs que retornam tipos variados, precisa lidar com formatos legados ou quer otimizar payloads, os recursos avançados da biblioteca fazem toda a diferença.\u003c/p\u003e\n\u003cp\u003eNeste artigo, vamos explorar \u003cstrong\u003epolimorfismo com sealed classes\u003c/strong\u003e, \u003cstrong\u003eserializers customizados\u003c/strong\u003e, \u003cstrong\u003eserialização contextual\u003c/strong\u003e e padrões avançados que resolvem problemas reais em projetos Kotlin. Se você já domina o básico, este guia vai elevar seu nível.\u003c/p\u003e","title":"Kotlin Serialization Avançada: Polimorfismo e Serializers Customizados | Kotlin Brasil"},{"content":"O Ktor é o framework HTTP nativo do ecossistema Kotlin, mantido pela JetBrains, e a versão 3.4.0 chegou com melhorias que impactam diretamente quem desenvolve APIs, microsserviços e aplicações em tempo real. Se você já usa Ktor para criar APIs ou está planejando migrar do Spring Boot, este artigo cobre tudo que mudou e como aproveitar na prática.\nNeste guia, vamos explorar as principais novidades: geração de documentação OpenAPI diretamente do código, streaming duplex com OkHttp, compressão Zstd, o novo plugin de ciclo de vida de requisições e várias outras melhorias.\nGeração de OpenAPI direto do código Uma das features mais pedidas pela comunidade finalmente chegou ao Ktor 3.4: a capacidade de gerar documentação OpenAPI dinamicamente a partir do código de roteamento, sem precisar manter um arquivo YAML ou JSON separado.\nA abordagem anterior exigia manter um arquivo openapi.yaml sincronizado manualmente com as rotas — um pesadelo de manutenção em projetos grandes. Agora, com o novo compiler plugin, a documentação vive junto do código:\nimport io.ktor.server.routing.* import io.ktor.server.response.* import io.ktor.http.* fun Route.messageRoutes() { get(\u0026#34;/messages\u0026#34;) { val query = call.parameters[\u0026#34;search\u0026#34;]?.parseQueryOrNull() call.respond(messageTable.listMessages(query)) }.describe { summary = \u0026#34;Lista todas as mensagens\u0026#34; description = \u0026#34;Retorna uma lista paginada de mensagens com filtro opcional.\u0026#34; parameters { query(\u0026#34;search\u0026#34;) { description = \u0026#34;Termo de busca para filtrar mensagens\u0026#34; required = false } query(\u0026#34;page\u0026#34;) { description = \u0026#34;Número da página (começando em 0)\u0026#34; required = false } } responses { HttpStatusCode.OK { description = \u0026#34;Lista de mensagens retornada com sucesso\u0026#34; schema = jsonSchema\u0026lt;List\u0026lt;Message\u0026gt;\u0026gt;() } HttpStatusCode.BadRequest { description = \u0026#34;Parâmetros de busca inválidos\u0026#34; } } } post(\u0026#34;/messages\u0026#34;) { val message = call.receive\u0026lt;CreateMessageRequest\u0026gt;() val created = messageTable.create(message) call.respond(HttpStatusCode.Created, created) }.describe { summary = \u0026#34;Cria uma nova mensagem\u0026#34; requestBody { schema = jsonSchema\u0026lt;CreateMessageRequest\u0026gt;() } responses { HttpStatusCode.Created { schema = jsonSchema\u0026lt;Message\u0026gt;() } } } } A função describe é uma extension function que se encaixa naturalmente no DSL de roteamento do Ktor. A documentação OpenAPI é gerada em runtime e pode ser exposta via endpoint dedicado, facilitando integração com Swagger UI ou outros clientes.\nSe você vem do Spring Boot, essa abordagem é similar ao SpringDoc, mas sem annotations — tudo via DSL Kotlin idiomático. Para uma implementação passo a passo com Swagger UI, YAML de contrato, exemplos de erro e checklist de CI, veja o tutorial prático de OpenAPI e Swagger no Ktor.\nStreaming duplex com OkHttp O Ktor 3.4 trouxe suporte a streaming duplex no cliente OkHttp, permitindo enviar dados no corpo da requisição e receber dados da resposta simultaneamente via HTTP/2. Isso é essencial para cenários como:\nUpload de arquivos grandes com feedback de progresso em tempo real Comunicação bidirecional sem WebSocket Streaming de dados de IA (como respostas de LLMs) A configuração é simples:\nimport io.ktor.client.* import io.ktor.client.engine.okhttp.* val client = HttpClient(OkHttp) { engine { duplexStreamingEnabled = true } } Com o duplex habilitado, você pode criar fluxos bidirecionais:\nclient.preparePost(\u0026#34;https://api.exemplo.com/stream\u0026#34;) { setBody(object : OutgoingContent.WriteChannelContent() { override suspend fun writeTo(channel: ByteWriteChannel) { // Envia dados progressivamente repeat(100) { i -\u0026gt; channel.writeStringUtf8(\u0026#34;chunk-$i\\n\u0026#34;) delay(100) } } }) }.execute { response -\u0026gt; // Recebe dados enquanto ainda está enviando val channel = response.bodyAsChannel() while (!channel.isClosedForRead) { val line = channel.readUTF8Line() ?: break println(\u0026#34;Recebido: $line\u0026#34;) } } Essa feature é especialmente útil se você trabalha com gRPC e Kotlin, já que o streaming bidirecional é um padrão comum em comunicação entre microsserviços.\nCompressão Zstd O Ktor 3.4 adicionou suporte nativo ao Zstd (Zstandard), o algoritmo de compressão desenvolvido pelo Facebook que oferece taxas de compressão superiores ao gzip com velocidade de descompressão significativamente maior.\nPara habilitar no servidor, basta instalar o módulo dedicado:\nimport io.ktor.server.plugins.compression.* fun Application.configureCompression() { install(Compression) { zstd { compressionLevel = 3 // Padrão: bom equilíbrio velocidade/compressão } gzip { priority = 0.9 } deflate { priority = 0.5 } } } O Zstd brilha em cenários onde você transmite payloads JSON grandes — como listas de produtos, logs ou dados analíticos. Em benchmarks internos da JetBrains, o Zstd com nível 3 comprime 20-30% melhor que gzip com velocidade de descompressão até 5x superior.\nA dependência é separada para não inflar projetos que não precisam:\n// build.gradle.kts dependencies { implementation(\u0026#34;io.ktor:ktor-server-compression-zstd:3.4.0\u0026#34;) } Plugin HttpRequestLifecycle O novo plugin HttpRequestLifecycle resolve um problema antigo: o que acontece com requisições em processamento quando o cliente desconecta? Antes do Ktor 3.4, a coroutine continuava executando até o final, desperdiçando recursos.\nAgora, com concorrência estruturada integrada ao ciclo de vida da requisição, operações em andamento são canceladas automaticamente:\nimport io.ktor.server.plugins.httprequestlifecycle.* fun Application.configureLifecycle() { install(HttpRequestLifecycle) routing { get(\u0026#34;/relatorio-pesado\u0026#34;) { // Se o cliente desconectar, esta coroutine é cancelada val dados = withContext(Dispatchers.IO) { // Consulta demorada ao banco de dados repository.gerarRelatorioCompleto() } call.respond(dados) } } } Essa feature é particularmente importante para operações que consomem muitos recursos, como geração de relatórios, processamento de imagens ou consultas complexas ao banco. Se você trabalha com observabilidade em Kotlin, o cancelamento adequado também gera métricas mais precisas sobre latência real.\nMelhorias em Server-Sent Events O suporte a SSE (Server-Sent Events) que foi introduzido no Ktor 3.0 recebeu melhorias de estabilidade e desempenho no 3.4. O SSE é ideal para cenários onde o servidor precisa enviar atualizações unidirecionais ao cliente — como notificações, feeds de dados ao vivo e dashboards:\nimport io.ktor.server.sse.* import io.ktor.sse.* fun Application.configureSSE() { install(SSE) routing { sse(\u0026#34;/eventos\u0026#34;) { // Envia eventos a cada segundo var contador = 0 while (true) { send(ServerSentEvent( data = \u0026#34;\u0026#34;\u0026#34;{\u0026#34;tipo\u0026#34;: \u0026#34;atualizacao\u0026#34;, \u0026#34;valor\u0026#34;: ${contador++}}\u0026#34;\u0026#34;\u0026#34;, event = \u0026#34;dados\u0026#34;, id = contador.toString() )) delay(1000) } } } } No lado do cliente, o Ktor também oferece suporte nativo:\nval client = HttpClient(CIO) client.sse(\u0026#34;https://api.exemplo.com/eventos\u0026#34;) { incoming.collect { evento -\u0026gt; println(\u0026#34;Evento recebido: ${evento.data}\u0026#34;) } } Se você está considerando entre SSE e WebSocket, o SSE é mais simples quando a comunicação é unidirecional (servidor para cliente) e funciona melhor com proxies e load balancers tradicionais.\nMigração e compatibilidade O Ktor 3.4 é totalmente compatível com o Kotlin 2.3.20 e funciona com o Kotlin 2.4.0 Beta sem problemas. A migração a partir do Ktor 3.x anterior é direta — basta atualizar a versão no Gradle:\n// build.gradle.kts val ktor_version = \u0026#34;3.4.0\u0026#34; dependencies { implementation(\u0026#34;io.ktor:ktor-server-core:$ktor_version\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-netty:$ktor_version\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-content-negotiation:$ktor_version\u0026#34;) implementation(\u0026#34;io.ktor:ktor-serialization-kotlinx-json:$ktor_version\u0026#34;) } Se você vem do Ktor 2.x, a migração é mais significativa devido à troca do kotlinx-io. Consulte o guia de backend com Ktor para mais detalhes sobre a arquitetura recomendada.\nConclusão O Ktor 3.4 consolida o framework como uma opção séria para backend em Kotlin, especialmente para equipes que valorizam a abordagem idiomática do Kotlin com coroutines e DSLs. A geração de OpenAPI via código elimina uma dor antiga, o streaming duplex abre novas possibilidades para aplicações em tempo real, e o Zstd melhora a performance de transferência de dados.\nSe você está avaliando frameworks para backend em Kotlin, vale conferir a comparação entre Ktor e Spring Boot para entender qual se encaixa melhor no seu cenário.\nPara quem trabalha com outras linguagens no backend, é interessante comparar a abordagem do Ktor com frameworks e padrões de Go para backend, que também priorizam simplicidade e performance, ou com o ecossistema de Python para APIs com FastAPI — cada linguagem traz suas vantagens dependendo do caso de uso.\n","permalink":"https://kotlin.dev.br/blog/ktor-3-4-novidades-openapi-streaming-2026/","summary":"\u003cp\u003eO Ktor é o framework HTTP nativo do ecossistema Kotlin, mantido pela JetBrains, e a versão \u003cstrong\u003e3.4.0\u003c/strong\u003e chegou com melhorias que impactam diretamente quem desenvolve APIs, microsserviços e aplicações em tempo real. Se você já usa \u003ca href=\"/blog/ktor-criando-apis-kotlin/\"\u003eKtor para criar APIs\u003c/a\u003e ou está planejando migrar do Spring Boot, este artigo cobre tudo que mudou e como aproveitar na prática.\u003c/p\u003e\n\u003cp\u003eNeste guia, vamos explorar as principais novidades: geração de documentação OpenAPI diretamente do código, streaming duplex com OkHttp, compressão Zstd, o novo plugin de ciclo de vida de requisições e várias outras melhorias.\u003c/p\u003e","title":"Ktor 3.4: OpenAPI, Streaming Duplex e Zstd no Kotlin | Kotlin Brasil"},{"content":"Sobre a vagaO iFood busca uma pessoa Engenheira de Software Backend Sênior para atuar na área de ADS em modelo remoto, com base em Osasco, São Paulo.\nTecnologias mencionadasKotlinGoAWSCopilotCursorReplitObservaçõesA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos ou benefícios.\n","permalink":"https://kotlin.dev.br/vagas/14ft06m7zjn881uj-ifood-engenheiro-a-de-software-backend-senior-ads/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa \u003cstrong\u003eEngenheira de Software Backend Sênior\u003c/strong\u003e para atuar na área de ADS em modelo remoto, com base em Osasco, São Paulo.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eGo\u003c/li\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eCopilot\u003c/li\u003e\u003cli\u003eCursor\u003c/li\u003e\u003cli\u003eReplit\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eObservações\u003c/h3\u003e\u003cp\u003eA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos ou benefícios.\u003c/p\u003e","title":"Engenheiro(a) de Software Backend Sênior - ADS"},{"content":"Sobre a vagaO JPMorgan Chase busca uma pessoa Engenheira de Software III para atuar em Payments Technology em São Paulo, com modelo presencial.\nResponsabilidadesDesenvolver, manter e evoluir sistemas de tecnologia para pagamentos.Construir e integrar APIs REST com foco em qualidade, segurança e confiabilidade.Colaborar com times de engenharia em soluções baseadas em cloud e infraestrutura como código.Implementar testes automatizados e apoiar práticas de entrega contínua.RequisitosExperiência com Kotlin e Java.Conhecimento em Spring Framework e desenvolvimento de APIs REST.Vivência com AWS, Kubernetes e Terraform.Experiência com Oracle e ambientes Linux.Prática com testes automatizados.Modelo de trabalhoVaga presencial em São Paulo, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/ij30bzhn89o7k1ad-jpmorgan-chase-engenheiro-a-de-software-iii-payments-technology/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO JPMorgan Chase busca uma pessoa Engenheira de Software III para atuar em Payments Technology em São Paulo, com modelo presencial.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver, manter e evoluir sistemas de tecnologia para pagamentos.\u003c/li\u003e\u003cli\u003eConstruir e integrar APIs REST com foco em qualidade, segurança e confiabilidade.\u003c/li\u003e\u003cli\u003eColaborar com times de engenharia em soluções baseadas em cloud e infraestrutura como código.\u003c/li\u003e\u003cli\u003eImplementar testes automatizados e apoiar práticas de entrega contínua.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin e Java.\u003c/li\u003e\u003cli\u003eConhecimento em Spring Framework e desenvolvimento de APIs REST.\u003c/li\u003e\u003cli\u003eVivência com AWS, Kubernetes e Terraform.\u003c/li\u003e\u003cli\u003eExperiência com Oracle e ambientes Linux.\u003c/li\u003e\u003cli\u003ePrática com testes automatizados.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em São Paulo, São Paulo, Brasil.\u003c/p\u003e","title":"Engenheiro(a) de Software III - Payments Technology"},{"content":"Sobre a vagaA Mitel busca uma pessoa estudante para estágio em Pesquisa e Desenvolvimento (P\u0026D) em Curitiba, Paraná.\nA vaga é presencial e não exige experiência prévia.\nTecnologiasKotlinPythonJavaScriptTypeScriptGoJavaNode.jsGitLocal de trabalhoCuritiba, Paraná, Brasil. Modelo presencial.\n","permalink":"https://kotlin.dev.br/vagas/u1aghu13xnu7ykyo-mitel-estagio-em-p-d/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Mitel busca uma pessoa estudante para estágio em Pesquisa e Desenvolvimento (P\u0026D) em Curitiba, Paraná.\u003c/p\u003e\u003cp\u003eA vaga é presencial e não exige experiência prévia.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003ePython\u003c/li\u003e\u003cli\u003eJavaScript\u003c/li\u003e\u003cli\u003eTypeScript\u003c/li\u003e\u003cli\u003eGo\u003c/li\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eNode.js\u003c/li\u003e\u003cli\u003eGit\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eCuritiba, Paraná, Brasil. Modelo presencial.\u003c/p\u003e","title":"Estágio em P\u0026D"},{"content":"Sobre a vagaO Mercado Livre busca uma pessoa Engenheira de Software Backend para atuar no Mercado Pago, em posição de nível pleno e modelo híbrido.\nA vaga é voltada ao desenvolvimento de soluções backend com Java, Kotlin, microserviços e sistemas distribuídos.\nResponsabilidadesDesenvolver e manter serviços backend para produtos do Mercado Pago.Trabalhar com arquitetura de microserviços e sistemas distribuídos.Escrever e manter testes unitários.Acompanhar qualidade, observabilidade e comportamento dos serviços em produção.Colaborar com times técnicos em decisões de implementação e evolução das soluções.RequisitosExperiência em desenvolvimento backend.Conhecimento em Java e Kotlin.Experiência com microserviços e sistemas distribuídos.Prática com testes unitários.Conhecimento em observabilidade.Interesse ou experiência no uso de ferramentas de IA no desenvolvimento de software.Local de trabalhoModelo híbrido, com atuação em Osasco ou América do Sul.\n","permalink":"https://kotlin.dev.br/vagas/cnyqa5wtfoh7r0e7-mercado-libre-engenheiro-a-de-software-backend-mercado-pago/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO Mercado Livre busca uma pessoa Engenheira de Software Backend para atuar no Mercado Pago, em posição de nível pleno e modelo híbrido.\u003c/p\u003e\u003cp\u003eA vaga é voltada ao desenvolvimento de soluções backend com Java, Kotlin, microserviços e sistemas distribuídos.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend para produtos do Mercado Pago.\u003c/li\u003e\u003cli\u003eTrabalhar com arquitetura de microserviços e sistemas distribuídos.\u003c/li\u003e\u003cli\u003eEscrever e manter testes unitários.\u003c/li\u003e\u003cli\u003eAcompanhar qualidade, observabilidade e comportamento dos serviços em produção.\u003c/li\u003e\u003cli\u003eColaborar com times técnicos em decisões de implementação e evolução das soluções.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento backend.\u003c/li\u003e\u003cli\u003eConhecimento em Java e Kotlin.\u003c/li\u003e\u003cli\u003eExperiência com microserviços e sistemas distribuídos.\u003c/li\u003e\u003cli\u003ePrática com testes unitários.\u003c/li\u003e\u003cli\u003eConhecimento em observabilidade.\u003c/li\u003e\u003cli\u003eInteresse ou experiência no uso de ferramentas de IA no desenvolvimento de software.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eModelo híbrido, com atuação em Osasco ou América do Sul.\u003c/p\u003e","title":"Engenheiro(a) de Software Backend - Mercado Pago"},{"content":"Sobre a vagaA Playlist busca um(a) Engenheiro(a) de Software Backend Staff para atuação remota no Brasil, em uma posição de senioridade avançada.\nStack e contexto técnicoLinguagens e tecnologias: Kotlin, Java, C#, Python, Ruby, React e SQL.Arquitetura e práticas: microsserviços, APIs, SDLC e metodologias ágeis.Observabilidade e suporte: New Relic e Kibana.RequisitosExperiência sênior em desenvolvimento Backend.Vivência com sistemas distribuídos, APIs e microsserviços.Capacidade de atuar em um ambiente remoto e colaborativo. ","permalink":"https://kotlin.dev.br/vagas/x5jfhgt7gmm5tnr9-playlist-engenheiro-a-de-software-backend-staff/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Playlist busca um(a) Engenheiro(a) de Software Backend Staff para atuação remota no Brasil, em uma posição de senioridade avançada.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLinguagens e tecnologias: Kotlin, Java, C#, Python, Ruby, React e SQL.\u003c/li\u003e\u003cli\u003eArquitetura e práticas: microsserviços, APIs, SDLC e metodologias ágeis.\u003c/li\u003e\u003cli\u003eObservabilidade e suporte: New Relic e Kibana.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Backend.\u003c/li\u003e\u003cli\u003eVivência com sistemas distribuídos, APIs e microsserviços.\u003c/li\u003e\u003cli\u003eCapacidade de atuar em um ambiente remoto e colaborativo.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Backend Staff"},{"content":"Sobre a vagaA Brex busca uma pessoa Engenheira de Software II, Produto, para atuar em São Paulo em modelo híbrido.\nResponsabilidadesDesenvolver e manter funcionalidades de produto.Trabalhar com APIs e integrações de sistemas.Colaborar com times de produto e engenharia na entrega de soluções escaláveis.RequisitosExperiência de nível pleno em engenharia de software.Experiência com Java, Kotlin ou Python.Conhecimento de SQL, NoSQL e desenvolvimento de APIs.Disponibilidade para atuação híbrida em São Paulo. ","permalink":"https://kotlin.dev.br/vagas/8vamgf27edngall2-brex-engenheiro-a-de-software-ii-produto/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Brex busca uma pessoa Engenheira de Software II, Produto, para atuar em São Paulo em modelo híbrido.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter funcionalidades de produto.\u003c/li\u003e\u003cli\u003eTrabalhar com APIs e integrações de sistemas.\u003c/li\u003e\u003cli\u003eColaborar com times de produto e engenharia na entrega de soluções escaláveis.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência de nível pleno em engenharia de software.\u003c/li\u003e\u003cli\u003eExperiência com Java, Kotlin ou Python.\u003c/li\u003e\u003cli\u003eConhecimento de SQL, NoSQL e desenvolvimento de APIs.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação híbrida em São Paulo.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software II, Produto"},{"content":"Se você já escreveu código Kotlin com MutableStateFlow, MutableLiveData ou qualquer padrão reativo, conhece bem o ritual: criar uma propriedade privada mutável prefixada com _ e expor uma versão pública somente leitura. Esse padrão de backing properties funciona, mas polui o código e escala mal. O Kotlin 2.3.0 introduziu os Explicit Backing Fields como feature experimental, e o Kotlin 2.4.0-Beta2 trouxe melhorias significativas rumo à estabilização.\nNeste guia, vamos entender o problema que essa feature resolve, como usar na prática e por que ela vai mudar a forma como você escreve propriedades em Kotlin.\nO problema das backing properties Considere um ViewModel típico em um projeto Android com Jetpack Compose:\nclass UserViewModel : ViewModel() { // Backing property mutável (privada) private val _userName = MutableStateFlow(\u0026#34;\u0026#34;) // Propriedade pública somente leitura val userName: StateFlow\u0026lt;String\u0026gt; = _userName.asStateFlow() private val _isLoading = MutableStateFlow(false) val isLoading: StateFlow\u0026lt;Boolean\u0026gt; = _isLoading.asStateFlow() private val _errorMessage = MutableStateFlow\u0026lt;String?\u0026gt;(null) val errorMessage: StateFlow\u0026lt;String?\u0026gt; = _errorMessage.asStateFlow() private val _userList = MutableStateFlow\u0026lt;List\u0026lt;User\u0026gt;\u0026gt;(emptyList()) val userList: StateFlow\u0026lt;List\u0026lt;User\u0026gt;\u0026gt; = _userList.asStateFlow() fun loadUsers() { viewModelScope.launch { _isLoading.value = true try { _userList.value = repository.getUsers() } catch (e: Exception) { _errorMessage.value = e.message } finally { _isLoading.value = false } } } } Repare no padrão: para cada estado, você precisa de duas declarações — a mutável com _ e a pública imutável. Com quatro estados, já são oito linhas só de declarações. Em ViewModels complexos com 10+ estados, isso vira um pesadelo de manutenção.\nO mesmo problema aparece com coleções. Se você quer expor uma List pública mas manipular uma MutableList internamente:\nclass TaskRepository { private val _tasks = mutableListOf\u0026lt;Task\u0026gt;() val tasks: List\u0026lt;Task\u0026gt; get() = _tasks.toList() fun addTask(task: Task) { _tasks.add(task) } } Como funcionam os Explicit Backing Fields Os Explicit Backing Fields introduzem uma sintaxe nova: você declara o campo de apoio diretamente dentro da propriedade usando a keyword field:\nclass UserViewModel : ViewModel() { val userName: StateFlow\u0026lt;String\u0026gt; field = MutableStateFlow(\u0026#34;\u0026#34;) val isLoading: StateFlow\u0026lt;Boolean\u0026gt; field = MutableStateFlow(false) val errorMessage: StateFlow\u0026lt;String?\u0026gt; field = MutableStateFlow\u0026lt;String?\u0026gt;(null) val userList: StateFlow\u0026lt;List\u0026lt;User\u0026gt;\u0026gt; field = MutableStateFlow\u0026lt;List\u0026lt;User\u0026gt;\u0026gt;(emptyList()) fun loadUsers() { viewModelScope.launch { isLoading.field.value = true try { userList.field.value = repository.getUsers() } catch (e: Exception) { errorMessage.field.value = e.message } finally { isLoading.field.value = false } } } } A diferença é clara: uma única declaração por propriedade. O tipo exposto publicamente é StateFlow\u0026lt;T\u0026gt; (somente leitura), mas internamente a classe tem acesso ao MutableStateFlow via field. O compilador faz o smart cast automaticamente dentro do escopo privado.\nSe você vem de Java migrando para Kotlin, essa feature elimina um dos padrões mais verbosos que os devs enfrentam na transição.\nHabilitando a feature Como a feature ainda é experimental, você precisa habilitar o opt-in. No build.gradle.kts:\n// build.gradle.kts kotlin { compilerOptions { freeCompilerArgs.add(\u0026#34;-Xexplicit-backing-fields\u0026#34;) } } Ou via anotação no arquivo:\n@file:OptIn(ExperimentalExplicitBackingFields::class) Exemplos práticos Coleções com tipo interno diferente Um caso clássico: expor uma lista imutável enquanto manipula uma lista mutável internamente:\nclass ShoppingCart { val items: List\u0026lt;CartItem\u0026gt; field = mutableListOf() fun addItem(item: CartItem) { field.add(item) // Acesso direto ao MutableList } fun removeItem(item: CartItem) { field.remove(item) } fun clear() { field.clear() } } Sem explicit backing fields, você precisaria do padrão _items / items com duas propriedades separadas. Agora, uma única propriedade resolve tudo.\nMap com acesso controlado class ConfigStore { val configs: Map\u0026lt;String, String\u0026gt; field = mutableMapOf() fun set(key: String, value: String) { field[key] = value } fun remove(key: String) { field.remove(key) } fun loadDefaults() { field.putAll( mapOf( \u0026#34;theme\u0026#34; to \u0026#34;dark\u0026#34;, \u0026#34;language\u0026#34; to \u0026#34;pt-br\u0026#34;, \u0026#34;notifications\u0026#34; to \u0026#34;enabled\u0026#34; ) ) } } Propriedade com validação e tipo interno Você pode combinar explicit backing fields com getters customizados:\nclass Temperature { val celsius: Double field = 0.0 get() = field val fahrenheit: Double get() = celsius * 9.0 / 5.0 + 32.0 fun update(newCelsius: Double) { require(newCelsius \u0026gt;= -273.15) { \u0026#34;Temperatura abaixo do zero absoluto\u0026#34; } celsius.field = newCelsius } } SharedFlow com buffer configurável class EventBus { val events: SharedFlow\u0026lt;AppEvent\u0026gt; field = MutableSharedFlow\u0026lt;AppEvent\u0026gt;( replay = 1, extraBufferCapacity = 64 ) suspend fun emit(event: AppEvent) { field.emit(event) } } Esse padrão é muito útil em projetos que usam Kotlin Flow para comunicação entre camadas.\nComparação: antes vs depois Vamos comparar um ViewModel real com e sem explicit backing fields:\nAntes (backing properties tradicionais) class ProductViewModel : ViewModel() { private val _products = MutableStateFlow\u0026lt;List\u0026lt;Product\u0026gt;\u0026gt;(emptyList()) val products: StateFlow\u0026lt;List\u0026lt;Product\u0026gt;\u0026gt; = _products.asStateFlow() private val _searchQuery = MutableStateFlow(\u0026#34;\u0026#34;) val searchQuery: StateFlow\u0026lt;String\u0026gt; = _searchQuery.asStateFlow() private val _selectedCategory = MutableStateFlow\u0026lt;Category?\u0026gt;(null) val selectedCategory: StateFlow\u0026lt;Category?\u0026gt; = _selectedCategory.asStateFlow() private val _isRefreshing = MutableStateFlow(false) val isRefreshing: StateFlow\u0026lt;Boolean\u0026gt; = _isRefreshing.asStateFlow() // 8 linhas de declarações para 4 estados } Depois (explicit backing fields) class ProductViewModel : ViewModel() { val products: StateFlow\u0026lt;List\u0026lt;Product\u0026gt;\u0026gt; field = MutableStateFlow\u0026lt;List\u0026lt;Product\u0026gt;\u0026gt;(emptyList()) val searchQuery: StateFlow\u0026lt;String\u0026gt; field = MutableStateFlow(\u0026#34;\u0026#34;) val selectedCategory: StateFlow\u0026lt;Category?\u0026gt; field = MutableStateFlow\u0026lt;Category?\u0026gt;(null) val isRefreshing: StateFlow\u0026lt;Boolean\u0026gt; field = MutableStateFlow(false) // 4 declarações claras para 4 estados } O resultado é um código 50% mais enxuto, sem convenções de nomes com underscore, e com o compilador garantindo type safety entre o tipo exposto e o tipo interno.\nInteração com outras features do Kotlin Com Sealed Classes Os explicit backing fields combinam bem com sealed classes para modelar estados de UI:\nsealed interface UiState\u0026lt;out T\u0026gt; { data object Loading : UiState\u0026lt;Nothing\u0026gt; data class Success\u0026lt;T\u0026gt;(val data: T) : UiState\u0026lt;T\u0026gt; data class Error(val message: String) : UiState\u0026lt;Nothing\u0026gt; } class DataViewModel : ViewModel() { val uiState: StateFlow\u0026lt;UiState\u0026lt;List\u0026lt;Item\u0026gt;\u0026gt;\u0026gt; field = MutableStateFlow\u0026lt;UiState\u0026lt;List\u0026lt;Item\u0026gt;\u0026gt;\u0026gt;(UiState.Loading) fun refresh() { viewModelScope.launch { uiState.field.value = UiState.Loading try { val items = repository.fetchItems() uiState.field.value = UiState.Success(items) } catch (e: Exception) { uiState.field.value = UiState.Error(e.message ?: \u0026#34;Erro desconhecido\u0026#34;) } } } } Com Scope Functions Você pode usar scope functions normalmente com o campo:\nclass Logger { val entries: List\u0026lt;LogEntry\u0026gt; field = mutableListOf() fun log(message: String) { LogEntry(message, System.currentTimeMillis()).also { field.add(it) } } } Quando usar (e quando não usar) Use explicit backing fields quando:\nA propriedade pública tem um tipo diferente da representação interna (ex: StateFlow vs MutableStateFlow) Você quer eliminar o padrão _propriedade / propriedade O campo precisa de inicialização específica diferente do tipo exposto Não use quando:\nO tipo interno é o mesmo do exposto — val e var tradicionais são suficientes Você precisa de compatibilidade com Kotlin \u0026lt; 2.3.0 O projeto ainda não pode usar features experimentais em produção Status e roadmap A feature foi introduzida como experimental no Kotlin 2.3.0 e recebeu melhorias no 2.4.0-Beta2. A expectativa é que se torne estável em uma release futura do Kotlin 2.4.x. Para acompanhar, confira o KEEP-430 no repositório oficial.\nSe você está testando as novidades do Kotlin 2.4.0-Beta2, confira também nosso artigo sobre Collection Literals, outra feature experimental que chegou nessa versão.\nConclusão Explicit Backing Fields resolvem um problema real e cotidiano do desenvolvimento Kotlin: a verbosidade das backing properties. Com uma sintaxe limpa e type-safe, a feature elimina duplicação, reduz erros de nomeação e torna ViewModels e repositórios significativamente mais legíveis.\nEmbora ainda experimental, vale a pena testar em projetos pessoais e módulos internos. Quando estabilizar, será uma das mudanças mais impactantes na forma como escrevemos propriedades em Kotlin.\nPara quem trabalha com outras linguagens da JVM, é interessante comparar como cada uma lida com encapsulamento de estado. Em Python, por exemplo, o padrão de properties com @property decorator resolve um problema similar, enquanto em Go o controle de visibilidade é feito por convenção de maiúsculas/minúsculas no nome.\n","permalink":"https://kotlin.dev.br/blog/kotlin-explicit-backing-fields-2026/","summary":"\u003cp\u003eSe você já escreveu código Kotlin com \u003ccode\u003eMutableStateFlow\u003c/code\u003e, \u003ccode\u003eMutableLiveData\u003c/code\u003e ou qualquer padrão reativo, conhece bem o ritual: criar uma propriedade privada mutável prefixada com \u003ccode\u003e_\u003c/code\u003e e expor uma versão pública somente leitura. Esse padrão de \u003cstrong\u003ebacking properties\u003c/strong\u003e funciona, mas polui o código e escala mal. O Kotlin 2.3.0 introduziu os \u003cstrong\u003eExplicit Backing Fields\u003c/strong\u003e como feature experimental, e o Kotlin 2.4.0-Beta2 trouxe melhorias significativas rumo à estabilização.\u003c/p\u003e\n\u003cp\u003eNeste guia, vamos entender o problema que essa feature resolve, como usar na prática e por que ela vai mudar a forma como você escreve propriedades em Kotlin.\u003c/p\u003e","title":"Explicit Backing Fields no Kotlin: Guia Completo | Kotlin Brasil"},{"content":"Se você trabalha com Kotlin Multiplatform e precisa integrar dependências iOS, provavelmente já enfrentou a dor de configurar CocoaPods ou lidar com frameworks manualmente. A boa notícia é que o suporte ao Swift Package Manager (SwiftPM) chegou como feature experimental no Kotlin 2.4.0-Beta2 — e promete simplificar drasticamente a forma como projetos KMP consomem bibliotecas do ecossistema Apple.\nNeste artigo, vamos explorar como funciona essa integração, como configurar seu projeto e quais são os benefícios e limitações atuais.\nPor que Swift Package Manager no KMP? O Swift Package Manager é o gerenciador de dependências oficial da Apple, integrado nativamente ao Xcode e ao ecossistema Swift. Até agora, projetos Kotlin Multiplatform que precisavam de dependências iOS tinham basicamente duas opções:\nCocoaPods: funcional, mas adiciona complexidade ao setup e exige Ruby instalado na máquina Frameworks manuais: flexível, mas trabalhoso de manter Com o suporte a SwiftPM, o plugin Gradle do Kotlin Multiplatform consegue importar APIs Objective-C e Swift diretamente de pacotes SwiftPM declarados nos seus targets Apple. Isso significa que você pode usar bibliotecas como Alamofire, Kingfisher ou qualquer outro pacote Swift sem sair do Gradle.\nSe você já leu nosso guia de Kotlin Multiplatform Mobile, essa novidade complementa perfeitamente aquele fluxo de trabalho.\nRequisitos Para usar a importação via SwiftPM, você precisa:\nKotlin 2.4.0-Beta2 ou superior Xcode 16 ou superior instalado (necessário para resolução de pacotes) Plugin Gradle do Kotlin Multiplatform atualizado Configurando o projeto A configuração acontece no bloco kotlin do seu build.gradle.kts. Veja um exemplo completo:\n// build.gradle.kts plugins { kotlin(\u0026#34;multiplatform\u0026#34;) version \u0026#34;2.4.0-Beta2\u0026#34; } kotlin { iosArm64() iosSimulatorArm64() iosX64() sourceSets { iosMain { dependencies { // Dependências Kotlin normais implementation(\u0026#34;io.ktor:ktor-client-darwin:3.1.2\u0026#34;) } } } // Configuração SwiftPM para targets Apple appleTargets { swiftPackageDependencies { // Pacote remoto via URL do repositório package(\u0026#34;Alamofire\u0026#34;) { url(\u0026#34;https://github.com/Alamofire/Alamofire.git\u0026#34;) from(\u0026#34;5.10.0\u0026#34;) } // Pacote local package(\u0026#34;MeuFrameworkInterno\u0026#34;) { path(\u0026#34;../ios-frameworks/MeuFramework\u0026#34;) } } } } Depois de configurar, o plugin Gradle resolve automaticamente as dependências SwiftPM durante o build, e você pode importar as APIs no código Kotlin:\n// src/iosMain/kotlin/networking/HttpClient.kt import cocoapods.Alamofire.AF import cocoapods.Alamofire.request class IosNetworkClient { fun fetchData(url: String, callback: (String?) -\u0026gt; Unit) { // Usando Alamofire diretamente do Kotlin AF.request(url).responseString { response -\u0026gt; callback(response.value) } } } Versionamento de dependências O SwiftPM no KMP suporta as mesmas estratégias de versionamento do Swift Package Manager nativo:\nswiftPackageDependencies { // Versão mínima (semver) package(\u0026#34;Biblioteca\u0026#34;) { url(\u0026#34;https://github.com/autor/biblioteca.git\u0026#34;) from(\u0026#34;2.0.0\u0026#34;) } // Range exato package(\u0026#34;OutraBiblioteca\u0026#34;) { url(\u0026#34;https://github.com/autor/outra.git\u0026#34;) exact(\u0026#34;1.5.3\u0026#34;) } // Branch específico package(\u0026#34;BibliotecaDev\u0026#34;) { url(\u0026#34;https://github.com/autor/dev.git\u0026#34;) branch(\u0026#34;main\u0026#34;) } } Mecanismo de lock: Package.resolved Para garantir builds reproduzíveis, o tooling do SwiftPM no KMP introduz um mecanismo de lock baseado em arquivos Package.resolved. Funciona assim:\nCada subprojeto gera seu próprio Package.resolved O plugin Gradle mescla todos em um único arquivo raiz Todos os subprojetos usam as mesmas versões resolvidas Isso é análogo ao gradle.lockfile ou ao package-lock.json — garante que toda a equipe e o CI usem exatamente as mesmas versões. Se você utiliza Gradle Version Catalogs no seu projeto, o SwiftPM complementa essa estratégia de versionamento centralizado.\nDependências transitivas Uma das grandes vantagens é que dependências transitivas são resolvidas automaticamente. Se o pacote A depende do pacote B, o plugin Gradle fornece o código de máquina necessário de B sem configuração adicional. Isso funciona tanto para testes Kotlin/Native quanto para linking de frameworks.\n// Não precisa declarar dependências transitivas manualmente // O plugin resolve automaticamente kotlin { appleTargets { swiftPackageDependencies { // Se Moya depende de Alamofire internamente, // Alamofire é resolvido automaticamente package(\u0026#34;Moya\u0026#34;) { url(\u0026#34;https://github.com/Moya/Moya.git\u0026#34;) from(\u0026#34;15.0.0\u0026#34;) } } } } Exemplo prático: app com analytics nativo Vamos montar um exemplo mais completo — um módulo KMP que usa uma biblioteca de analytics nativa do iOS via SwiftPM:\n// shared/build.gradle.kts kotlin { androidTarget() iosArm64() iosSimulatorArm64() appleTargets { swiftPackageDependencies { package(\u0026#34;TelemetryDeck\u0026#34;) { url(\u0026#34;https://github.com/TelemetryDeck/SwiftSDK.git\u0026#34;) from(\u0026#34;2.0.0\u0026#34;) } } } sourceSets { commonMain { dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2\u0026#34;) } } } } No código compartilhado, você usa o padrão expect/actual para abstrair a implementação:\n// src/commonMain/kotlin/analytics/Analytics.kt expect class AnalyticsTracker { fun trackEvent(name: String, params: Map\u0026lt;String, String\u0026gt;) } // src/iosMain/kotlin/analytics/Analytics.ios.kt import cocoapods.TelemetryDeck.TelemetryManager actual class AnalyticsTracker { actual fun trackEvent(name: String, params: Map\u0026lt;String, String\u0026gt;) { TelemetryManager.send(name, with = params) } } Esse padrão funciona muito bem com a arquitetura que descrevemos no artigo sobre Kotlin Multiplatform.\nSwiftPM vs CocoaPods no KMP Aspecto SwiftPM CocoaPods Setup Apenas Gradle Requer Ruby + Podfile Integração Xcode Nativa Via plugin Dependências transitivas Automáticas Automáticas Lock file Package.resolved Podfile.lock Pacotes locais Suportado Suportado Exportar KMP como pacote Ainda não Suportado Maturidade no KMP Experimental Estável Para projetos novos, o SwiftPM tende a ser a escolha mais natural — especialmente se a equipe iOS já usa SwiftPM em projetos nativos. Para projetos existentes com CocoaPods funcionando, a migração pode esperar até a feature ficar estável.\nLimitações atuais Como feature experimental, existem algumas limitações importantes:\nExportação não suportada: você pode importar pacotes SwiftPM, mas ainda não pode exportar módulos KMP como Swift packages Xcode obrigatório: a resolução de pacotes depende do Xcode, então CI Linux puro não funciona para targets Apple Opt-in necessário: por ser experimental, mudanças na API podem ocorrer entre releases Para acompanhar a evolução, fique de olho no roadmap oficial do Kotlin e nas atualizações que trazemos aqui no blog.\nMigrando de CocoaPods para SwiftPM Se você já tem um projeto KMP usando CocoaPods e quer migrar gradualmente:\nIdentifique quais dependências iOS possuem suporte a SwiftPM (a maioria das bibliotecas populares já tem) Adicione o bloco swiftPackageDependencies mantendo o cocoapods existente Migre uma dependência por vez, testando cada mudança Remova o bloco cocoapods quando todas as dependências estiverem no SwiftPM Se você trabalha com coroutines no seu projeto KMP, a boa notícia é que o SwiftPM não interfere em nada no funcionamento — as suspend functions continuam funcionando normalmente com os wrappers nativos.\nConclusão O suporte a Swift Package Manager no Kotlin Multiplatform é um passo importante para tornar a integração iOS mais natural e menos dependente de ferramentas externas. Embora ainda experimental, a feature já está funcional o suficiente para experimentar em projetos novos ou módulos isolados.\nCom o KotlinConf 2026 se aproximando (maio, em Munique), é provável que tenhamos novidades sobre a estabilização dessa feature. Enquanto isso, aproveite para testar e dar feedback à equipe do Kotlin.\nSe você desenvolve para múltiplas plataformas, vale conferir como outras linguagens abordam o problema: em Go, o gerenciamento de módulos é nativo desde o Go 1.11, enquanto em Rust, o Cargo resolve dependências de forma similar ao que o SwiftPM propõe para o ecossistema Apple.\n","permalink":"https://kotlin.dev.br/blog/kotlin-swift-package-manager-kmp-ios-2026/","summary":"\u003cp\u003eSe você trabalha com \u003cstrong\u003eKotlin Multiplatform\u003c/strong\u003e e precisa integrar dependências iOS, provavelmente já enfrentou a dor de configurar CocoaPods ou lidar com frameworks manualmente. A boa notícia é que o suporte ao \u003cstrong\u003eSwift Package Manager (SwiftPM)\u003c/strong\u003e chegou como feature experimental no Kotlin 2.4.0-Beta2 — e promete simplificar drasticamente a forma como projetos KMP consomem bibliotecas do ecossistema Apple.\u003c/p\u003e\n\u003cp\u003eNeste artigo, vamos explorar como funciona essa integração, como configurar seu projeto e quais são os benefícios e limitações atuais.\u003c/p\u003e","title":"Swift Package Manager no KMP: Guia Prático | Kotlin Brasil"},{"content":"Quando alguém fala em Kotlin, a primeira associação geralmente é Android ou backend com Spring Boot. Mas existe um lado menos explorado da linguagem que pode mudar sua produtividade no dia a dia: Kotlin Script. Com arquivos .main.kts, você escreve e executa scripts diretamente — sem compilar, sem criar projeto, sem main(). Basta um arquivo e o comando kotlin no terminal.\nNeste artigo, vamos explorar como usar Kotlin como linguagem de scripting para automação, tarefas DevOps, processamento de dados e tudo mais que você hoje faz com Bash ou Python. Se você já programa em Kotlin, vai aproveitar todo o type safety, null safety e a biblioteca padrão que já conhece — agora em scripts rápidos e descartáveis.\nO que é Kotlin Script? Kotlin Script é a capacidade de executar código Kotlin diretamente, sem precisar de um projeto estruturado com build.gradle.kts, sem declarar uma função main() e sem etapa explícita de compilação. Você cria um arquivo com extensão .main.kts, escreve código top-level e executa com kotlin script.main.kts.\nO formato .main.kts é o padrão oficial mantido pela JetBrains. Ele suporta:\nCódigo top-level (sem precisar de classes ou funções main) Importação de dependências Maven via anotações @file:DependsOn Resolução automática de repositórios com @file:Repository Imports implícitos da biblioteca padrão do Kotlin Suporte nativo no IntelliJ IDEA com autocomplete e highlighting Se você já trabalha com Gradle Kotlin DSL, já usa Kotlin Script sem perceber — os arquivos build.gradle.kts e settings.gradle.kts são scripts Kotlin.\nPrimeiros passos Pré-requisitos Você precisa do Kotlin instalado na máquina. Se já tem o IntelliJ IDEA, o compilador vem junto. Caso contrário, instale via SDKMAN:\n// Terminal // sdk install kotlin Ou via Homebrew no macOS:\n// Terminal // brew install kotlin Verifique a instalação:\n// Terminal // kotlin -version // Kotlin version 2.3.20-release (JRE 21.0.3+9) Se você quer um guia completo de setup, confira como instalar Kotlin.\nSeu primeiro script Crie um arquivo chamado ola.main.kts:\n// ola.main.kts val nome = \u0026#34;Kotlin Brasil\u0026#34; val versao = KotlinVersion.CURRENT println(\u0026#34;Olá do $nome!\u0026#34;) println(\u0026#34;Rodando Kotlin $versao\u0026#34;) println(\u0026#34;Data: ${java.time.LocalDate.now()}\u0026#34;) Execute no terminal:\n// Terminal // kotlin ola.main.kts // Olá do Kotlin Brasil! // Rodando Kotlin 2.3.20 // Data: 2026-04-24 Nenhum fun main(), nenhum class, nenhum build. O código roda direto. A primeira execução pode demorar alguns segundos para compilação em cache, mas execuções subsequentes são muito mais rápidas.\nAdicionando dependências externas A feature mais poderosa do .main.kts é a capacidade de importar bibliotecas Maven diretamente no script com anotações:\n// relatorio.main.kts @file:DependsOn(\u0026#34;com.squareup.okhttp3:okhttp:4.12.0\u0026#34;) @file:DependsOn(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1\u0026#34;) import okhttp3.OkHttpClient import okhttp3.Request import kotlinx.serialization.json.* val client = OkHttpClient() val request = Request.Builder() .url(\u0026#34;https://api.github.com/repos/JetBrains/kotlin\u0026#34;) .build() val response = client.newCall(request).execute() val json = Json.parseToJsonElement(response.body!!.string()) val stars = json.jsonObject[\u0026#34;stargazers_count\u0026#34;] val forks = json.jsonObject[\u0026#34;forks_count\u0026#34;] val language = json.jsonObject[\u0026#34;language\u0026#34;] println(\u0026#34;Repositório Kotlin no GitHub:\u0026#34;) println(\u0026#34; Estrelas: $stars\u0026#34;) println(\u0026#34; Forks: $forks\u0026#34;) println(\u0026#34; Linguagem: $language\u0026#34;) As dependências são baixadas automaticamente do Maven Central na primeira execução e cacheadas para as próximas. Se precisar de um repositório diferente, use @file:Repository:\n@file:Repository(\u0026#34;https://jitpack.io\u0026#34;) @file:DependsOn(\u0026#34;com.github.usuario:biblioteca:1.0.0\u0026#34;) Isso é semelhante ao que fazemos no Gradle Version Catalog, mas para scripts avulsos.\nCasos de uso práticos Automação de deploy Um script para verificar o status de containers Docker e notificar via webhook:\n// check-deploy.main.kts @file:DependsOn(\u0026#34;com.squareup.okhttp3:okhttp:4.12.0\u0026#34;) import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.MediaType.Companion.toMediaType data class Container(val nome: String, val status: String, val uptime: String) fun verificarContainers(): List\u0026lt;Container\u0026gt; { val process = ProcessBuilder(\u0026#34;docker\u0026#34;, \u0026#34;ps\u0026#34;, \u0026#34;--format\u0026#34;, \u0026#34;{{.Names}}|{{.Status}}\u0026#34;) .redirectErrorStream(true) .start() return process.inputStream.bufferedReader().readLines() .filter { it.isNotBlank() } .map { linha -\u0026gt; val partes = linha.split(\u0026#34;|\u0026#34;) Container( nome = partes[0], status = if (partes[1].startsWith(\u0026#34;Up\u0026#34;)) \u0026#34;running\u0026#34; else \u0026#34;stopped\u0026#34;, uptime = partes[1] ) } } val containers = verificarContainers() val parados = containers.filter { it.status == \u0026#34;stopped\u0026#34; } if (parados.isNotEmpty()) { println(\u0026#34;ALERTA: ${parados.size} container(s) parado(s):\u0026#34;) parados.forEach { println(\u0026#34; - ${it.nome}: ${it.uptime}\u0026#34;) } } else { println(\u0026#34;Todos os ${containers.size} containers estão rodando.\u0026#34;) } Se você trabalha com Kubernetes ou Docker, scripts como esse substituem Bash com a vantagem de type safety e tratamento de erros robusto.\nProcessamento de CSV Ler um CSV de funcionários e gerar estatísticas — algo que muitos fazem em Python:\n// analise-salarios.main.kts import java.io.File data class Funcionario( val nome: String, val departamento: String, val salario: Double, val experiencia: Int ) val funcionarios = File(\u0026#34;funcionarios.csv\u0026#34;) .readLines() .drop(1) // pular header .map { linha -\u0026gt; val campos = linha.split(\u0026#34;,\u0026#34;) Funcionario( nome = campos[0].trim(), departamento = campos[1].trim(), salario = campos[2].trim().toDouble(), experiencia = campos[3].trim().toInt() ) } println(\u0026#34;Total de funcionários: ${funcionarios.size}\u0026#34;) println(\u0026#34;Salário médio: R$ ${\u0026#34;%.2f\u0026#34;.format(funcionarios.map { it.salario }.average())}\u0026#34;) println() // Agrupamento por departamento funcionarios.groupBy { it.departamento } .toSortedMap() .forEach { (depto, funcs) -\u0026gt; val media = funcs.map { it.salario }.average() println(\u0026#34;$depto: ${funcs.size} pessoas, média R$ ${\u0026#34;%.2f\u0026#34;.format(media)}\u0026#34;) } println() // Top 5 salários println(\u0026#34;Top 5 salários:\u0026#34;) funcionarios.sortedByDescending { it.salario } .take(5) .forEachIndexed { i, f -\u0026gt; println(\u0026#34; ${i + 1}. ${f.nome} (${f.departamento}): R$ ${\u0026#34;%.2f\u0026#34;.format(f.salario)}\u0026#34;) } Perceba como as collections do Kotlin — groupBy, sortedByDescending, map, average — tornam o processamento de dados expressivo e conciso, comparável ao Python.\nGeração de código e scaffolding Criar arquivos de projeto automaticamente:\n// scaffold.main.kts import java.io.File val pacote = args.getOrElse(0) { \u0026#34;com.exemplo\u0026#34; } val nome = args.getOrElse(1) { \u0026#34;MeuProjeto\u0026#34; } val diretorios = listOf( \u0026#34;src/main/kotlin/${pacote.replace(\u0026#39;.\u0026#39;, \u0026#39;/\u0026#39;)}\u0026#34;, \u0026#34;src/main/resources\u0026#34;, \u0026#34;src/test/kotlin/${pacote.replace(\u0026#39;.\u0026#39;, \u0026#39;/\u0026#39;)}\u0026#34;, \u0026#34;src/test/resources\u0026#34; ) diretorios.forEach { File(it).mkdirs() } File(\u0026#34;src/main/kotlin/${pacote.replace(\u0026#39;.\u0026#39;, \u0026#39;/\u0026#39;)}/Application.kt\u0026#34;).writeText(\u0026#34;\u0026#34;\u0026#34; package $pacote fun main() { println(\u0026#34;$nome iniciado com sucesso!\u0026#34;) } \u0026#34;\u0026#34;\u0026#34;.trimIndent()) File(\u0026#34;build.gradle.kts\u0026#34;).writeText(\u0026#34;\u0026#34;\u0026#34; plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.3.20\u0026#34; application } group = \u0026#34;$pacote\u0026#34; version = \u0026#34;1.0.0\u0026#34; application { mainClass.set(\u0026#34;$pacote.ApplicationKt\u0026#34;) } repositories { mavenCentral() } dependencies { testImplementation(kotlin(\u0026#34;test\u0026#34;)) } \u0026#34;\u0026#34;\u0026#34;.trimIndent()) println(\u0026#34;Projeto \u0026#39;$nome\u0026#39; criado com sucesso!\u0026#34;) println(\u0026#34;Pacote: $pacote\u0026#34;) println(\u0026#34;Diretórios criados: ${diretorios.size}\u0026#34;) Execute com: kotlin scaffold.main.kts com.kotlinbrasil MeuApp\nKotlin Script vs Bash vs Python Uma comparação honesta para decidir quando usar cada um:\nKotlin Script vence quando Você já é dev Kotlin e quer aproveitar o conhecimento existente O script precisa de type safety e tratamento de null safety robusto Você quer usar bibliotecas Java/Kotlin existentes (OkHttp, kotlinx-serialization, etc.) O script pode crescer e eventualmente virar um projeto — a migração é trivial Integração com CI/CD onde o ambiente já tem Kotlin Bash vence quando São operações simples de sistema de arquivos (mover, copiar, renomear) Pipes e redirecionamento são a ferramenta certa O ambiente pode não ter JVM instalada O script tem menos de 20 linhas Python vence quando Data science pesado com NumPy, Pandas, matplotlib O time não conhece Kotlin Prototipagem rápida de ML (embora o Kotlin Notebook esteja fechando essa lacuna) Se você quer uma comparação mais profunda entre Kotlin e Python como linguagens, confira nosso artigo Kotlin vs Python. Para automação e scripting, Python continua sendo referência, mas o Kotlin Script brilha quando você quer type safety e acesso ao ecossistema JVM. Já para automação de infra e CLIs performáticas, Go é uma alternativa forte com binários estáticos e compilação rápida.\nDicas avançadas Shebang para execução direta No Linux e macOS, adicione um shebang no início do script para executá-lo diretamente:\n#!/usr/bin/env kotlin // meu-script.main.kts println(\u0026#34;Executando diretamente!\u0026#34;) println(\u0026#34;Argumentos: ${args.joinToString()}\u0026#34;) Depois torne executável com chmod +x meu-script.main.kts e rode com ./meu-script.main.kts.\nIDE support no IntelliJ O IntelliJ IDEA reconhece arquivos .main.kts nativamente. Você ganha:\nAutocomplete completo, incluindo dependências declaradas com @file:DependsOn Highlighting de sintaxe e erros em tempo real Botão de run direto no editor Navegação para código-fonte das dependências Isso é uma vantagem significativa sobre Bash, onde o suporte de IDE é limitado. Se você usa VS Code, o suporte a .main.kts é mais básico, mas funcional.\nCache e performance A primeira execução de um script .main.kts é mais lenta porque o Kotlin precisa compilar e resolver dependências. Execuções subsequentes usam cache e são significativamente mais rápidas. Se performance de cold start é crítica, considere compilar o script para um JAR com kotlinc -script script.main.kts.\nPara scripts que rodam em pipelines de CI/CD, o cache de dependências Maven ajuda bastante.\nLimitações e futuro Algumas limitações atuais do Kotlin Script:\nCold start — a primeira execução compila o script, o que leva alguns segundos. Para scripts que rodam uma vez e somem (como em cron jobs), isso pode importar Sem suporte a Kotlin Multiplatform — scripts rodam apenas na JVM, não em Native ou WASM Debugging limitado — embora o IntelliJ suporte breakpoints em .main.kts, a experiência não é tão polida quanto em projetos estruturados kscript em manutenção — a ferramenta kscript, que adicionava features como cache agressivo e execução em background, não recebe atualizações desde 2023. A recomendação atual é usar .main.kts nativo ou JBang como alternativa A JetBrains confirmou que continuará investindo em .main.kts como o formato oficial de scripting. Melhorias em IDE support e performance de cold start estão no roadmap para versões futuras do Kotlin.\nQuando migrar um script para um projeto Se seu script .main.kts começa a crescer além de 200-300 linhas, considere migrar para um projeto Kotlin estruturado. Sinais de que é hora de migrar:\nVocê precisa de múltiplos arquivos ou módulos O script precisa de testes automatizados — veja nosso post sobre Power-Assert para testes sem dependências externas Distribuição para outros devs que podem não ter o Kotlin instalado Performance de startup importa e você quer compilar para um fat JAR A migração é simples: o código Kotlin é o mesmo, você só precisa mover de top-level para dentro de funções e adicionar um build.gradle.kts. Toda a lógica, extension functions e imports continuam funcionando.\nPerguntas frequentes Posso usar coroutines em Kotlin Script? Sim. Adicione @file:DependsOn(\u0026quot;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2\u0026quot;) e use coroutines normalmente. Você vai precisar de runBlocking como entry point, já que o script roda em contexto top-level.\nKotlin Script funciona no Windows? Sim. Desde que o Kotlin esteja instalado e no PATH, funciona em Windows, Linux e macOS. O shebang (#!/usr/bin/env kotlin) funciona apenas em sistemas Unix.\nPosso acessar argumentos da linha de comando? Sim. A variável args (do tipo Array\u0026lt;String\u0026gt;) está disponível automaticamente em scripts .main.kts, similar ao args da função main() em projetos Kotlin convencionais.\nComo usar Kotlin Script em pipelines de CI/CD? Instale o Kotlin no runner de CI e execute com kotlin script.main.kts. Em GitHub Actions, você pode usar a action setup-kotlin para configurar o ambiente. Para Gitea Actions, o setup é similar.\n","permalink":"https://kotlin.dev.br/blog/kotlin-script-kts-automacao-2026/","summary":"\u003cp\u003eQuando alguém fala em Kotlin, a primeira associação geralmente é Android ou backend com \u003ca href=\"/blog/kotlin-spring-boot/\"\u003eSpring Boot\u003c/a\u003e. Mas existe um lado menos explorado da linguagem que pode mudar sua produtividade no dia a dia: \u003cstrong\u003eKotlin Script\u003c/strong\u003e. Com arquivos \u003ccode\u003e.main.kts\u003c/code\u003e, você escreve e executa scripts diretamente — sem compilar, sem criar projeto, sem \u003ccode\u003emain()\u003c/code\u003e. Basta um arquivo e o comando \u003ccode\u003ekotlin\u003c/code\u003e no terminal.\u003c/p\u003e\n\u003cp\u003eNeste artigo, vamos explorar como usar Kotlin como linguagem de scripting para automação, tarefas DevOps, processamento de dados e tudo mais que você hoje faz com Bash ou Python. Se você já programa em Kotlin, vai aproveitar todo o type safety, null safety e a biblioteca padrão que já conhece — agora em scripts rápidos e descartáveis.\u003c/p\u003e","title":"Kotlin Script (.kts): Automação e Scripts sem Compilar | Kotlin Brasil"},{"content":"Se você já escreveu testes em Kotlin, sabe que uma das maiores dores de cabeça é decifrar mensagens de erro genéricas. Aquele AssertionError: expected true but was false que não diz absolutamente nada sobre o que deu errado. Para resolver isso, muita gente recorre a bibliotecas como AssertJ ou Kotest Assertions — mas e se o próprio compilador pudesse gerar mensagens detalhadas automaticamente?\nÉ exatamente isso que o Power-Assert faz. Trata-se de um plugin oficial do compilador Kotlin, mantido pela JetBrains, que transforma assertions simples em mensagens ricas mostrando o valor de cada subexpressão. Neste artigo, vamos configurar o Power-Assert do zero, explorar exemplos práticos e entender quando ele substitui (ou complementa) bibliotecas de assertion tradicionais.\nSe você já domina o básico de testes em Kotlin, confira nosso guia completo de testes com JUnit 5 e MockK para contexto adicional.\nO que é o Power-Assert? O Power-Assert é um plugin do compilador Kotlin (não uma biblioteca runtime) que intercepta chamadas a funções como assert(), require(), check() e assertTrue() durante a compilação. Quando uma assertion falha, em vez de exibir uma mensagem genérica, ele gera um diagrama mostrando o valor de cada variável e expressão intermediária.\nO conceito nasceu com o Groovy Power Assert e foi adaptado para Kotlin por Brian Norman no projeto kotlin-power-assert. A partir do Kotlin 2.0, a JetBrains integrou o plugin oficialmente ao compilador K2, tornando-o um cidadão de primeira classe do ecossistema.\nDiferente de bibliotecas como AssertJ que exigem uma API fluente (assertThat(valor).isEqualTo(esperado)), o Power-Assert funciona com o assert nativo do Kotlin. Você escreve código idiomático e o compilador faz o trabalho pesado.\nConfigurando o Power-Assert no Gradle A configuração é feita no build.gradle.kts. Primeiro, adicione o plugin:\n// build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.3.20\u0026#34; kotlin(\u0026#34;plugin.power-assert\u0026#34;) version \u0026#34;2.3.20\u0026#34; } Em seguida, configure quais funções o plugin deve transformar:\nimport org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi @OptIn(ExperimentalKotlinGradlePluginApi::class) powerAssert { functions = listOf( \u0026#34;kotlin.assert\u0026#34;, \u0026#34;kotlin.require\u0026#34;, \u0026#34;kotlin.check\u0026#34;, \u0026#34;kotlin.test.assertTrue\u0026#34;, \u0026#34;kotlin.test.assertEquals\u0026#34;, \u0026#34;kotlin.test.assertNull\u0026#34; ) } Não esqueça de adicionar a dependência de testes:\ndependencies { testImplementation(kotlin(\u0026#34;test\u0026#34;)) } Se você usa Gradle com Kotlin DSL, esse setup já é familiar. O plugin funciona com Kotlin 2.0+ e é compatível com projetos Kotlin Multiplatform — basta configurar os includedSourceSets adequados.\nComo funciona na prática Vamos começar com um exemplo simples. Considere este teste:\nimport kotlin.test.Test class UsuarioTest { @Test fun `nome do usuario deve ter pelo menos 3 caracteres`() { val nome = \u0026#34;Al\u0026#34; assert(nome.length \u0026gt;= 3) { \u0026#34;Nome muito curto\u0026#34; } } } Sem o Power-Assert, a falha exibe apenas:\nNome muito curto Com o Power-Assert habilitado, a saída vira:\nNome muito curto assert(nome.length \u0026gt;= 3) { \u0026#34;Nome muito curto\u0026#34; } | | | Al 2 false Cada subexpressão é decomposta e alinhada verticalmente. Você vê imediatamente que nome vale \u0026quot;Al\u0026quot;, que length é 2 e que a comparação \u0026gt;= 3 resultou em false. Sem precisar adicionar logs ou usar debugger.\nExemplo com expressões complexas O Power-Assert brilha quando a assertion envolve múltiplas condições:\ndata class Funcionario(val nome: String, val idade: Int, val salario: Double) @Test fun `dados do funcionario devem ser validos`() { val func = Funcionario(\u0026#34;Carlos\u0026#34;, 150, 8500.0) assert(func.idade in 18..65 \u0026amp;\u0026amp; func.salario \u0026gt; 5000.0 \u0026amp;\u0026amp; func.nome.isNotBlank()) } A saída do Power-Assert:\nAssertion failed assert(func.idade in 18..65 \u0026amp;\u0026amp; func.salario \u0026gt; 5000.0 \u0026amp;\u0026amp; func.nome.isNotBlank()) | | | | | 150 false false Funcionario(nome=Carlos, idade=150, salario=8500.0) Repare que o plugin identifica exatamente qual parte da expressão falhou (idade in 18..65 retornou false) e mostra o valor 150. Isso é infinitamente mais útil do que um AssertionError genérico.\nUsando com assertTrue e assertEquals O plugin não se limita ao assert. Quando você configura kotlin.test.assertTrue e kotlin.test.assertEquals na lista de funções, eles também ganham mensagens detalhadas:\nimport kotlin.test.Test import kotlin.test.assertTrue import kotlin.test.assertEquals class CalculadoraTest { fun somar(a: Int, b: Int) = a + b @Test fun `soma deve retornar valor correto`() { val resultado = somar(2, 3) assertEquals(6, resultado) } @Test fun `resultado deve ser positivo e par`() { val valor = somar(3, 4) assertTrue(valor \u0026gt; 0 \u0026amp;\u0026amp; valor % 2 == 0) } } No segundo teste, a saída mostra:\nAssertion failed assertTrue(valor \u0026gt; 0 \u0026amp;\u0026amp; valor % 2 == 0) | | | | | 7 true 7 1 false Fica claro que 7 % 2 resulta em 1, que não é igual a 0. Se você usa JUnit 5 com MockK no dia a dia, o Power-Assert complementa bem o workflow sem exigir mudanças na sua API de testes.\nSoft assertions com Power-Assert Uma técnica avançada é combinar o Power-Assert com soft assertions — onde múltiplas falhas são coletadas e reportadas juntas no final do teste, em vez de parar na primeira:\ninterface AssertScope { fun assert(assertion: Boolean, message: (() -\u0026gt; String)? = null) } class AssertScopeImpl : AssertScope { val errors = mutableListOf\u0026lt;String\u0026gt;() override fun assert(assertion: Boolean, message: (() -\u0026gt; String)?) { if (!assertion) { errors.add(message?.invoke() ?: \u0026#34;Assertion failed\u0026#34;) } } } fun \u0026lt;R\u0026gt; assertSoftly(block: AssertScope.() -\u0026gt; R): R { val scope = AssertScopeImpl() val result = scope.block() if (scope.errors.isNotEmpty()) { throw AssertionError(scope.errors.joinToString(\u0026#34;\\n\u0026#34;)) } return result } Para que o Power-Assert transforme a função assert dentro do AssertScope, adicione-a na configuração:\npowerAssert { functions = listOf( \u0026#34;kotlin.assert\u0026#34;, \u0026#34;com.exemplo.AssertScope.assert\u0026#34; // sua função customizada ) } Isso funciona porque o Power-Assert aceita qualquer função cujo último parâmetro seja String ou () -\u0026gt; String. Você pode criar suas próprias funções de assertion e o plugin gera os diagramas automaticamente.\nQuando usar e quando não usar O Power-Assert é excelente para:\nTestes unitários com assertions simples usando assert, assertTrue, assertEquals Validações em tempo de execução com require() e check() — veja nosso artigo sobre null safety para contexto Projetos que valorizam simplicidade e não querem adicionar bibliotecas de assertion pesadas Projetos multiplataforma via KMP onde você quer assertions consistentes em todas as plataformas Porém, ele não substitui completamente bibliotecas como Kotest Assertions quando você precisa de:\nMatchers especializados (coleções, strings, exceções) Assertions assíncronas para coroutines e Flow DSLs de assertion complexas com encadeamento fluente A melhor abordagem é combinar: use Power-Assert para assertions diretas e uma biblioteca complementar para casos mais sofisticados. Se você está montando uma suíte de testes do zero, confira nosso tutorial de testes unitários para a base.\nLimitações atuais Algumas coisas para ficar atento:\nO plugin é experimental — a API pode mudar entre versões do Kotlin, embora esteja estável desde o Kotlin 2.0 Requer K2 — funciona apenas com o compilador K2 (Kotlin 2.0+). Se seu projeto ainda usa o compilador legado, será preciso migrar primeiro Expressões inline geram melhor output — se você armazena o resultado de uma subexpressão em uma variável antes do assert, o diagrama perde contexto Não funciona com assertThat do AssertJ ou APIs fluentes — o Power-Assert precisa de uma expressão booleana direta Power-Assert no contexto do ecossistema Kotlin O Power-Assert se encaixa na filosofia do Kotlin de oferecer ferramentas poderosas integradas ao compilador. Assim como as sealed classes eliminaram a necessidade de bibliotecas de pattern matching, e as data classes substituíram geradores de boilerplate, o Power-Assert reduz a dependência de bibliotecas externas para testes.\nSe você trabalha com Spring Boot e Kotlin, a integração é transparente — basta adicionar o plugin ao Gradle e seus testes existentes com assert ganham mensagens melhores sem nenhuma mudança de código.\nPara quem está montando um projeto novo, confira também nosso post sobre Kotlin Scripting — outra feature subestimada do ecossistema que complementa bem a experiência de desenvolvimento. Se você trabalha com outras linguagens, vale comparar: Rust já oferece mensagens de assert detalhadas nativamente, e Go usa uma abordagem diferente com testify — cada ecossistema resolve testes de um jeito.\nPerguntas frequentes O Power-Assert funciona com Kotlin Multiplatform? Sim. O plugin suporta KMP nativamente. Basta configurar os includedSourceSets para incluir os source sets desejados (commonTest, jvmTest, iosTest, etc.).\nPreciso remover minhas bibliotecas de assertion existentes? Nao. O Power-Assert complementa bibliotecas como Kotest e AssertJ. Você pode usar ambos no mesmo projeto sem conflitos.\nO Power-Assert afeta a performance dos testes? O impacto é insignificante. A transformação acontece em tempo de compilacao, nao em runtime. O unico overhead adicional e a construcao das mensagens de erro quando uma assertion falha — o que so ocorre em cenarios de falha.\nFunciona com Gradle Version Catalog? Sim. Basta declarar o plugin no version catalog e referencia-lo no build.gradle.kts usando o alias definido no catalogo.\n","permalink":"https://kotlin.dev.br/blog/kotlin-power-assert-plugin-testes-2026/","summary":"\u003cp\u003eSe você já escreveu testes em Kotlin, sabe que uma das maiores dores de cabeça é decifrar mensagens de erro genéricas. Aquele \u003ccode\u003eAssertionError: expected true but was false\u003c/code\u003e que não diz absolutamente nada sobre o que deu errado. Para resolver isso, muita gente recorre a bibliotecas como AssertJ ou Kotest Assertions — mas e se o próprio compilador pudesse gerar mensagens detalhadas automaticamente?\u003c/p\u003e\n\u003cp\u003eÉ exatamente isso que o \u003cstrong\u003ePower-Assert\u003c/strong\u003e faz. Trata-se de um plugin oficial do compilador Kotlin, mantido pela JetBrains, que transforma assertions simples em mensagens ricas mostrando o valor de cada subexpressão. Neste artigo, vamos configurar o Power-Assert do zero, explorar exemplos práticos e entender quando ele substitui (ou complementa) bibliotecas de assertion tradicionais.\u003c/p\u003e","title":"Kotlin Power-Assert: Assertions Legíveis sem Bibliotecas | Kotlin Brasil"},{"content":"Sobre a vagaA ArcTouch busca Desenvolvedor Android Sênior para banco de talentos, em modelo remoto no Brasil.\nResponsabilidadesAtuar no desenvolvimento de aplicações Android.Trabalhar com Kotlin, Android SDK e Jetpack.Integrar aplicações a APIs RESTful.Colaborar com o versionamento de código usando Git.RequisitosExperiência sênior em desenvolvimento Android.Conhecimento em Kotlin, Android SDK e Jetpack.Experiência com integração de APIs RESTful.Familiaridade com Git. ","permalink":"https://kotlin.dev.br/vagas/4tvof4qmdzfl3vsv-arctouch-desenvolvedor-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA ArcTouch busca Desenvolvedor Android Sênior para banco de talentos, em modelo remoto no Brasil.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAtuar no desenvolvimento de aplicações Android.\u003c/li\u003e\u003cli\u003eTrabalhar com Kotlin, Android SDK e Jetpack.\u003c/li\u003e\u003cli\u003eIntegrar aplicações a APIs RESTful.\u003c/li\u003e\u003cli\u003eColaborar com o versionamento de código usando Git.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Android SDK e Jetpack.\u003c/li\u003e\u003cli\u003eExperiência com integração de APIs RESTful.\u003c/li\u003e\u003cli\u003eFamiliaridade com Git.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Android Sênior"},{"content":"Sobre a vagaA ArcTouch busca um Engenheiro Android Sênior para atuar remotamente em uma oportunidade de contrato, como parte de um banco de talentos.\nResponsabilidadesDesenvolver e manter aplicações Android com Kotlin e Android SDK.Construir interfaces e funcionalidades usando Jetpack Compose.Aplicar padrões de arquitetura como MVVM e MVP.Integrar aplicações com APIs RESTful.Colaborar com controle de versão em Git e pipelines de CI/CD.RequisitosExperiência sênior em desenvolvimento Android.Conhecimento sólido em Kotlin, Android SDK e Jetpack Compose.Experiência com MVVM, MVP e princípios S.O.L.I.D.Prática com APIs RESTful, Git e CI/CD. ","permalink":"https://kotlin.dev.br/vagas/szkuo0qw3soqt4nz-arctouch-engenheiro-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA ArcTouch busca um Engenheiro Android Sênior para atuar remotamente em uma oportunidade de contrato, como parte de um banco de talentos.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android com Kotlin e Android SDK.\u003c/li\u003e\u003cli\u003eConstruir interfaces e funcionalidades usando Jetpack Compose.\u003c/li\u003e\u003cli\u003eAplicar padrões de arquitetura como MVVM e MVP.\u003c/li\u003e\u003cli\u003eIntegrar aplicações com APIs RESTful.\u003c/li\u003e\u003cli\u003eColaborar com controle de versão em Git e pipelines de CI/CD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin, Android SDK e Jetpack Compose.\u003c/li\u003e\u003cli\u003eExperiência com MVVM, MVP e princípios S.O.L.I.D.\u003c/li\u003e\u003cli\u003ePrática com APIs RESTful, Git e CI/CD.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro Android Sênior"},{"content":"Sobre a vagaA Brex busca uma pessoa Engenheira de Software Sênior para atuar com infraestrutura de releases em São Paulo, em modelo híbrido.\nFoco técnicoAutomação e evolução de pipelines de CI/CD e processos de release.Trabalho com ferramentas como GitHub Actions, CircleCI, Buildkite, Argo, Spinnaker e Jenkins.Ambientes em cloud com AWS, GCP ou Azure.Infraestrutura com Docker, Kubernetes, Terraform e CloudFormation.RequisitosExperiência sênior em engenharia de software ou infraestrutura de desenvolvimento.Conhecimento em linguagens como Kotlin, Java, Go ou Python.Experiência com SQL, NoSQL e ferramentas de observabilidade.Disponibilidade para atuar em modelo híbrido em São Paulo. ","permalink":"https://kotlin.dev.br/vagas/gi8r8gvwfv10y2h4-brex-engenheiro-a-de-software-senior-infra-de-releases/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Brex busca uma pessoa Engenheira de Software Sênior para atuar com infraestrutura de releases em São Paulo, em modelo híbrido.\u003c/p\u003e\u003ch3\u003eFoco técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAutomação e evolução de pipelines de CI/CD e processos de release.\u003c/li\u003e\u003cli\u003eTrabalho com ferramentas como GitHub Actions, CircleCI, Buildkite, Argo, Spinnaker e Jenkins.\u003c/li\u003e\u003cli\u003eAmbientes em cloud com AWS, GCP ou Azure.\u003c/li\u003e\u003cli\u003eInfraestrutura com Docker, Kubernetes, Terraform e CloudFormation.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software ou infraestrutura de desenvolvimento.\u003c/li\u003e\u003cli\u003eConhecimento em linguagens como Kotlin, Java, Go ou Python.\u003c/li\u003e\u003cli\u003eExperiência com SQL, NoSQL e ferramentas de observabilidade.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuar em modelo híbrido em São Paulo.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Sênior, Infra de Releases"},{"content":"Durante muito tempo, falar em persistência local no Kotlin Multiplatform significava cair quase sempre em SQLDelight, wrappers próprios ou soluções diferentes para cada plataforma. Em 2026, esse cenário mudou bastante: o Room amadureceu seu suporte a KMP e já virou uma alternativa concreta para times Android que querem compartilhar entidades, DAOs e parte importante da camada de dados com iOS e outras plataformas.\nNeste artigo, vamos ver como o Room funciona no mundo multiplataforma, quando faz sentido adotá-lo, como configurar commonMain, qual o papel dos drivers SQLite e quais cuidados você precisa ter para não tratar KMP como “Android com nomes diferentes”.\nSe você ainda está construindo a base do assunto, vale revisar antes nosso guia de Kotlin Multiplatform Mobile, o tutorial de KMP e o artigo sobre o futuro do Kotlin Multiplatform.\nO que mudou para o Room no Kotlin Multiplatform? A principal novidade é que o Room 2.7+ passou a oferecer suporte real para Kotlin Multiplatform, permitindo definir em commonMain boa parte da estrutura que antes ficava presa ao Android:\nentidades (@Entity); interfaces DAO (@Dao); definição do banco (@Database); queries compartilhadas; retorno reativo com Flow. Isso aproxima muito a experiência de quem já conhece Room no Android. Em vez de abandonar completamente o conhecimento acumulado do ecossistema Jetpack, você reaproveita conceitos, anotações e parte da ergonomia.\nPara times brasileiros que já mantêm app Android em Kotlin e querem evoluir para iOS com mais compartilhamento, esse é um salto importante. É o mesmo tipo de ganho gradual que comentamos em Kotlin para Android e em comparações como Kotlin Multiplatform vs Flutter.\nQuando vale usar Room em KMP? A resposta curta é: quando seu time já tem afinidade com o ecossistema AndroidX e quer reduzir a distância entre Android e KMP.\nRoom em KMP faz mais sentido quando: a equipe já domina Room no Android; a camada de dados precisa ser compartilhada entre Android e iOS; você quer continuar usando entidades e DAOs com uma API familiar; o projeto já segue arquitetura com repositórios e Flow; existe interesse em reduzir soluções paralelas entre plataformas. Talvez não seja a melhor escolha quando: o projeto já está consolidado com SQLDelight e sem dores reais; a equipe precisa de suporte muito específico fora do modelo Room; a base multiplataforma ainda é experimental e muda demais; você quer o mínimo possível de acoplamento com AndroidX. Como quase toda decisão arquitetural, isso depende mais do contexto do que de hype. O mesmo raciocínio vale quando discutimos monólito modular com Kotlin e Spring ou gRPC com Kotlin: a ferramenta certa é a que reduz complexidade real.\nDependências e plugins Um setup moderno de Room com KMP pode começar assim:\n// shared/build.gradle.kts plugins { kotlin(\u0026#34;multiplatform\u0026#34;) id(\u0026#34;com.google.devtools.ksp\u0026#34;) id(\u0026#34;androidx.room\u0026#34;) } kotlin { androidTarget() iosX64() iosArm64() iosSimulatorArm64() sourceSets { commonMain.dependencies { implementation(\u0026#34;androidx.room:room-runtime:2.8.4\u0026#34;) implementation(\u0026#34;androidx.sqlite:sqlite-bundled:2.6.2\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1\u0026#34;) } } } dependencies { add(\u0026#34;kspAndroid\u0026#34;, \u0026#34;androidx.room:room-compiler:2.8.4\u0026#34;) add(\u0026#34;kspIosX64\u0026#34;, \u0026#34;androidx.room:room-compiler:2.8.4\u0026#34;) add(\u0026#34;kspIosArm64\u0026#34;, \u0026#34;androidx.room:room-compiler:2.8.4\u0026#34;) add(\u0026#34;kspIosSimulatorArm64\u0026#34;, \u0026#34;androidx.room:room-compiler:2.8.4\u0026#34;) } room { schemaDirectory(\u0026#34;$projectDir/schemas\u0026#34;) } Dois pontos merecem atenção:\nKSP por target — em KMP, você precisa configurar o compilador do Room para cada alvo relevante. Schema versionada — salvar schemas continua sendo uma boa prática para evolução do banco e revisão de migrações. Se você já acompanha o tema de tooling, aproveite também nosso conteúdo sobre KSP em Kotlin e Gradle Version Catalog, porque ambos ajudam a manter essa configuração organizada.\nEstruturando o banco em commonMain Aqui está a grande virada conceitual: em vez de deixar entidade e DAO presas ao Android, você move o núcleo do banco para commonMain.\nEntidade compartilhada import androidx.room.Entity import androidx.room.PrimaryKey @Entity(tableName = \u0026#34;artigos\u0026#34;) data class ArtigoEntity( @PrimaryKey(autoGenerate = true) val id: Long = 0, val slug: String, val titulo: String, val categoria: String, val favorito: Boolean = false, ) DAO compartilhado import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query import kotlinx.coroutines.flow.Flow @Dao interface ArtigoDao { @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun salvar(item: ArtigoEntity) @Query(\u0026#34;SELECT * FROM artigos ORDER BY titulo ASC\u0026#34;) fun listarTodos(): Flow\u0026lt;List\u0026lt;ArtigoEntity\u0026gt;\u0026gt; @Query(\u0026#34;SELECT * FROM artigos WHERE favorito = 1\u0026#34;) fun listarFavoritos(): Flow\u0026lt;List\u0026lt;ArtigoEntity\u0026gt;\u0026gt; @Query(\u0026#34;UPDATE artigos SET favorito = :favorito WHERE slug = :slug\u0026#34;) suspend fun atualizarFavorito(slug: String, favorito: Boolean) } Banco compartilhado import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.ConstructedBy @Database( entities = [ArtigoEntity::class], version = 1, exportSchema = true, ) @ConstructedBy(AppDatabaseConstructor::class) abstract class AppDatabase : RoomDatabase() { abstract fun artigoDao(): ArtigoDao } Essa API deixa a modelagem muito mais alinhada com o restante do código compartilhado. Para projetos que já usam Flow e camadas reativas, o encaixe é natural.\nO papel do @ConstructedBy e do construtor esperado Em KMP, o Room precisa de uma forma multiplataforma para inicializar a implementação gerada do banco. Por isso aparece o padrão com expect object:\nimport androidx.room.RoomDatabaseConstructor @Suppress(\u0026#34;KotlinNoActualForExpect\u0026#34;) expect object AppDatabaseConstructor : RoomDatabaseConstructor\u0026lt;AppDatabase\u0026gt; { override fun initialize(): AppDatabase } Esse padrão parece estranho à primeira vista, mas segue a mesma lógica do expect/actual que você já encontra no ecossistema KMP. Se quiser reforçar esse conceito, vale passar pelo nosso glossário sobre expect/actual.\nDrivers SQLite: por que eles importam tanto? No Android puro, muita gente quase nunca pensa profundamente no driver do banco, porque a plataforma já entrega quase tudo de forma implícita. No KMP, isso muda. Você precisa escolher como o Room conversa com SQLite em cada alvo.\nOpção recomendada: BundledSQLiteDriver Na maioria dos casos, a melhor escolha é o BundledSQLiteDriver(), porque ele entrega comportamento mais consistente entre plataformas.\nimport androidx.sqlite.driver.bundled.BundledSQLiteDriver import kotlinx.coroutines.Dispatchers fun criarBanco(builder: androidx.room.RoomDatabase.Builder\u0026lt;AppDatabase\u0026gt;): AppDatabase { return builder .setDriver(BundledSQLiteDriver()) .setQueryCoroutineContext(Dispatchers.IO) .build() } Essa consistência é valiosa porque reduz diferenças inesperadas entre Android e iOS. Em times menores, isso economiza bastante tempo de investigação.\nAlternativas por plataforma Dependendo do cenário, você também pode trabalhar com drivers específicos, como:\nAndroidSQLiteDriver no Android; NativeSQLiteDriver no iOS. Mas, para a maior parte dos casos novos, o driver bundled tende a simplificar a vida.\nCriando o builder por plataforma Mesmo com o banco definido em commonMain, o caminho físico do arquivo ainda depende da plataforma. Por isso, o builder costuma ser criado localmente em cada target.\nAndroid import android.content.Context import androidx.room.Room fun provideDatabaseBuilder(context: Context): androidx.room.RoomDatabase.Builder\u0026lt;AppDatabase\u0026gt; { val dbFile = context.applicationContext.getDatabasePath(\u0026#34;kotlin_brasil.db\u0026#34;) return Room.databaseBuilder\u0026lt;AppDatabase\u0026gt;( context = context.applicationContext, name = dbFile.absolutePath, ) } iOS import androidx.room.Room import platform.Foundation.NSHomeDirectory fun provideDatabaseBuilder(): androidx.room.RoomDatabase.Builder\u0026lt;AppDatabase\u0026gt; { val dbPath = NSHomeDirectory() + \u0026#34;/Documents/kotlin_brasil.db\u0026#34; return Room.databaseBuilder\u0026lt;AppDatabase\u0026gt;( name = dbPath, ) } A ideia é simples: a estrutura do banco é compartilhada, mas o local do arquivo ainda é responsabilidade de cada ambiente.\nRepositório compartilhado com Flow Com o DAO em commonMain, seu repositório pode ficar bastante limpo:\nimport kotlinx.coroutines.flow.Flow class ArtigoRepository( private val dao: ArtigoDao, ) { fun listarFavoritos(): Flow\u0026lt;List\u0026lt;ArtigoEntity\u0026gt;\u0026gt; { return dao.listarFavoritos() } suspend fun salvarArtigo(slug: String, titulo: String, categoria: String) { dao.salvar( ArtigoEntity( slug = slug, titulo = titulo, categoria = categoria, ) ) } suspend fun alternarFavorito(slug: String, favorito: Boolean) { dao.atualizarFavorito(slug, favorito) } } Se a sua UI Android usa Compose e a iOS usa bindings próprios, ambas podem consumir a mesma regra de persistência. Esse é justamente o tipo de compartilhamento que torna o KMP interessante no mundo real.\nDiferenças importantes em relação ao Room Android clássico Aqui está um ponto essencial: Room em KMP não é só o Room Android transportado de plataforma. Existem diferenças práticas.\n1. Flow tende a ser a escolha natural Em código compartilhado, Flow funciona melhor do que abordagens ligadas ao Android, como LiveData.\n2. Algumas APIs Android-only não existem Recursos específicos do Android podem não estar disponíveis da mesma forma no ambiente multiplataforma.\n3. Queries cruas e transações exigem atenção Dependendo do caso, você vai usar APIs específicas do modelo KMP, inclusive para acesso por conexões de leitura e escrita.\n4. Testes precisam cobrir mais de um ambiente mental Mesmo que você não rode todos os testes em todas as plataformas o tempo todo, vale validar que sua modelagem não assume detalhes exclusivos do Android.\nEsse cuidado é parecido com o que discutimos em Compose Multiplatform 1.10.6 e em Kotlin Multiplatform vs React Native: o segredo é respeitar o que é compartilhável e o que continua sendo específico de plataforma.\nExemplo de uso na camada de apresentação Vamos imaginar um ViewModel compartilhado para artigos favoritos:\nclass FavoritosViewModel( private val repository: ArtigoRepository, ) : ViewModel() { val favoritos = repository.listarFavoritos() .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = emptyList(), ) fun alternarFavorito(slug: String, favorito: Boolean) { viewModelScope.launch { repository.alternarFavorito(slug, favorito) } } } Num app Android com Compose, isso encaixa muito bem com telas declarativas. Num projeto iOS, a mesma base compartilhada continua útil, desde que a camada de apresentação esteja preparada para consumir esse estado.\nBoas práticas para usar Room em KMP Se você está avaliando adoção, estas recomendações ajudam bastante:\n1. Comece com uma feature simples Não migre toda a persistência do app de uma vez. Pilote com favoritos, cache de artigos, onboarding ou configurações locais.\n2. Prefira modelos pequenos e estáveis Evite entidades gigantes logo no começo. Quanto menor a superfície, mais fácil validar o comportamento multiplataforma.\n3. Padronize o uso de Flow Se a estratégia da equipe já é reativa, manter essa consistência facilita integração com UI e testes.\n4. Versione schemas desde o início Mesmo em projeto novo, deixe a evolução do banco previsível.\n5. Documente limites da camada compartilhada Nem toda necessidade de banco precisa estar em commonMain. Às vezes é melhor compartilhar 80% com qualidade do que forçar 100% e aumentar atrito.\nRoom em KMP substitui SQLDelight? Não necessariamente. O que mudou é que agora existe uma opção mais forte dentro do universo AndroidX. Em alguns times, isso vai tornar o Room a escolha natural. Em outros, SQLDelight continuará fazendo mais sentido.\nO ganho real é ter escolha madura. E isso é ótimo para o ecossistema Kotlin em 2026.\nConclusão O suporte do Room ao Kotlin Multiplatform é uma das evoluções mais práticas do ecossistema recente. Ele não transforma KMP em solução mágica, mas reduz bastante a fricção para equipes Android que querem compartilhar persistência local sem abandonar ferramentas familiares.\nSe o seu time já domina Room, trabalha com Flow e está levando KMP mais a sério, estudar essa stack faz muito sentido agora. Para muita gente, ela representa o caminho mais confortável entre o mundo Android tradicional e uma arquitetura realmente multiplataforma.\nE esse talvez seja o principal valor da novidade: permitir que a adoção de KMP aconteça de forma mais incremental, com menos reinvenção e mais reaproveitamento de conhecimento já consolidado. Para quem trabalha com persistência em outras linguagens, vale comparar como Rust usa SQLx e Diesel para acesso a banco com type safety em tempo de compilação — uma filosofia parecida com o que o Room oferece no ecossistema Kotlin.\nPerguntas Frequentes Room funciona em Kotlin Multiplatform de verdade? Sim. As versões recentes do Room já oferecem suporte a KMP, permitindo compartilhar entidades, DAOs e definição do banco em commonMain, com builders específicos por plataforma.\nPreciso usar KSP com Room no KMP? Sim, na prática o KSP continua sendo parte importante do setup, e normalmente você precisa configurar os targets relevantes para geração de código.\nQual driver SQLite usar no Room multiplataforma? Na maioria dos casos novos, o BundledSQLiteDriver() é a escolha mais simples e previsível, porque mantém o comportamento mais consistente entre plataformas.\nRoom em KMP é melhor que SQLDelight? Não existe resposta universal. Para times já acostumados com AndroidX e Room, a adoção pode ser mais natural. Para outros cenários, SQLDelight ainda pode ser a melhor opção.\nO banco fica 100% compartilhado entre Android e iOS? A estrutura principal pode ser compartilhada, mas o builder e o caminho físico do arquivo continuam específicos por plataforma. Ou seja: o núcleo compartilha bastante, mas nem tudo é idêntico.\n","permalink":"https://kotlin.dev.br/blog/room-kotlin-multiplatform-2026/","summary":"\u003cp\u003eDurante muito tempo, falar em persistência local no \u003cstrong\u003eKotlin Multiplatform\u003c/strong\u003e significava cair quase sempre em SQLDelight, wrappers próprios ou soluções diferentes para cada plataforma. Em 2026, esse cenário mudou bastante: o \u003cstrong\u003eRoom\u003c/strong\u003e amadureceu seu suporte a KMP e já virou uma alternativa concreta para times Android que querem compartilhar entidades, DAOs e parte importante da camada de dados com iOS e outras plataformas.\u003c/p\u003e\n\u003cp\u003eNeste artigo, vamos ver como o Room funciona no mundo multiplataforma, quando faz sentido adotá-lo, como configurar \u003ccode\u003ecommonMain\u003c/code\u003e, qual o papel dos drivers SQLite e quais cuidados você precisa ter para não tratar KMP como “Android com nomes diferentes”.\u003c/p\u003e","title":"Room no Kotlin Multiplatform: Banco Compartilhado em 2026 | Kotlin Brasil"},{"content":"Se você desenvolve apps Android com Compose, 2026 trouxe uma mudança importante: o Navigation 3 saiu do campo de curiosidade para virar uma opção real de arquitetura. A proposta é simples de entender, mas poderosa na prática: tratar navegação como estado da UI, com back stack tipada, integração melhor com Compose e APIs mais modernas para transições, overlays e predictive back.\nNeste guia, você vai entender o que é o Navigation 3, quando ele faz sentido, como configurar o projeto e como montar um fluxo de navegação idiomático em Kotlin. A ideia aqui não é hype. É mostrar onde essa biblioteca realmente ajuda, especialmente em apps novos ou em times que já abraçaram Compose por completo.\nSe você ainda está consolidando a base do ecossistema Android, vale revisar também nosso guia de Jetpack Compose, o tutorial de Compose para iniciantes, o conteúdo sobre Kotlin para Android e o guia de App Links e deep links com Kotlin para conectar navegação interna a URLs reais de produto.\nO que é o Navigation 3? O Navigation 3 é a nova biblioteca de navegação do AndroidX pensada com uma abordagem Compose-first. Em vez de herdar a mentalidade do mundo de Fragments, ela parte da ideia de que telas, overlays e fluxo de ida e volta devem ser representados como estado serializável.\nNa prática, isso significa algumas vantagens importantes:\nchaves de navegação tipadas; back stack controlada diretamente pelo seu estado; integração natural com Compose; suporte melhor para cenários modernos, como predictive back; base mais limpa para animações, overlays e resultados entre destinos. Se você já comparou paradigmas de UI moderna em artigos como Jetpack Compose vs XML, vai perceber que o Navigation 3 segue a mesma filosofia: menos acoplamento com infra antiga e mais foco em estado declarativo.\nPor que o Navigation 3 importa em 2026? Durante muito tempo, muita gente usou o Navigation Compose tradicional e resolveu o problema. E tudo bem: ele continua útil. O ponto é que o Navigation 3 tenta corrigir algumas dores recorrentes em apps totalmente declarativos:\nBack stack mais explícita — você manipula uma estrutura de navegação clara, em vez de depender de abstrações mais opacas. Melhor alinhamento com serialização — as chaves são tipos reais, não apenas strings e rotas improvisadas. Mais controle para experiências modernas — overlays, resultados entre telas e transições ficam mais naturais. Arquitetura mais previsível — navegação vira parte do estado da aplicação, o que combina com MVI, MVVM e fluxos reativos. Se o seu time já trabalha com coroutines, Flow e telas orientadas a estado, a curva de adoção é muito mais tranquila.\nDependências do projeto Um setup inicial pode começar assim:\n// build.gradle.kts plugins { id(\u0026#34;com.android.application\u0026#34;) kotlin(\u0026#34;android\u0026#34;) kotlin(\u0026#34;plugin.serialization\u0026#34;) } android { namespace = \u0026#34;br.dev.exemplo\u0026#34; compileSdk = 36 defaultConfig { applicationId = \u0026#34;br.dev.exemplo\u0026#34; minSdk = 24 targetSdk = 36 versionCode = 1 versionName = \u0026#34;1.0\u0026#34; } buildFeatures { compose = true } } dependencies { implementation(\u0026#34;androidx.navigation3:navigation3-runtime:1.1.1\u0026#34;) implementation(\u0026#34;androidx.navigation3:navigation3-ui:1.1.1\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0\u0026#34;) } A parte do kotlin(\u0026quot;plugin.serialization\u0026quot;) é importante porque as chaves de navegação normalmente são serializáveis. Se você ainda não domina esse recurso, vale ler nosso glossário sobre serialization e o post sobre Kotlin Multiplatform, já que a modelagem serializável aparece em vários contextos modernos do ecossistema.\nModelando destinos tipados Uma das ideias mais legais do Navigation 3 é parar de navegar por strings mágicas. Em vez disso, você define tipos:\nimport kotlinx.serialization.Serializable @Serializable object Home @Serializable data class DetalheArtigo(val slug: String) @Serializable object Favoritos @Serializable data class Perfil(val userId: String) Isso já melhora a manutenção do projeto. Quando você muda um destino, o compilador passa a ajudar. É o mesmo ganho de segurança que a gente vê quando troca lógica frágil por sealed classes ou adota null safety.\nPrimeiro fluxo com rememberNavBackStack Agora vamos montar uma navegação simples entre home e detalhe:\nimport androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.foundation.layout.* import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.navigation3.runtime.rememberNavBackStack import androidx.navigation3.ui.NavDisplay import androidx.navigation3.ui.entryProvider import androidx.navigation3.ui.entry @Composable fun AppNavigation() { val backStack = rememberNavBackStack(Home) NavDisplay( backStack = backStack, entryProvider = entryProvider { entry\u0026lt;Home\u0026gt; { HomeScreen( onAbrirArtigo = { slug -\u0026gt; backStack.add(DetalheArtigo(slug)) }, onAbrirFavoritos = { backStack.add(Favoritos) } ) } entry\u0026lt;DetalheArtigo\u0026gt; { destino -\u0026gt; DetalheArtigoScreen( slug = destino.slug, onVoltar = { backStack.removeLastOrNull() } ) } entry\u0026lt;Favoritos\u0026gt; { FavoritosScreen( onVoltar = { backStack.removeLastOrNull() } ) } } ) } Perceba o padrão: a sua pilha é um estado Compose, e a UI renderiza conforme esse estado. Isso conversa muito bem com arquiteturas que já usam MVVM ou fluxos baseados em reducer.\nExemplo de telas reais Vamos imaginar um app de conteúdo técnico em Kotlin:\n@Composable fun HomeScreen( onAbrirArtigo: (String) -\u0026gt; Unit, onAbrirFavoritos: () -\u0026gt; Unit, ) { Scaffold( topBar = { TopAppBar(title = { Text(\u0026#34;Kotlin Brasil App\u0026#34;) }) } ) { padding -\u0026gt; Column( modifier = Modifier .fillMaxSize() .padding(padding) .padding(24.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { Button(onClick = { onAbrirArtigo(\u0026#34;navigation-3-compose-android-2026\u0026#34;) }) { Text(\u0026#34;Abrir artigo sobre Navigation 3\u0026#34;) } OutlinedButton(onClick = onAbrirFavoritos) { Text(\u0026#34;Ver favoritos\u0026#34;) } } } } @Composable fun DetalheArtigoScreen( slug: String, onVoltar: () -\u0026gt; Unit, ) { Scaffold( topBar = { TopAppBar( title = { Text(\u0026#34;Detalhe do artigo\u0026#34;) }, navigationIcon = { TextButton(onClick = onVoltar) { Text(\u0026#34;Voltar\u0026#34;) } } ) } ) { padding -\u0026gt; Column( modifier = Modifier .fillMaxSize() .padding(padding) .padding(24.dp) ) { Text(\u0026#34;Slug recebido: $slug\u0026#34;) } } } Essa abordagem evita muito boilerplate. E como a chave DetalheArtigo já carrega o slug, você reduz o risco de navegar com argumentos inconsistentes.\nQuando o Navigation 3 é melhor que o Navigation Compose tradicional? A resposta honesta é: depende do momento do projeto.\nVale mais a pena quando: o app é 100% Compose; o time quer navegação realmente orientada a estado; há preocupação com tipagem forte e serialização; o roadmap inclui transições mais sofisticadas, overlays ou predictive back; o projeto ainda não carregou legado forte de Fragments. Talvez não valha migrar agora quando: o app atual já está estável com Navigation Compose tradicional; a equipe tem pouco tempo para revisar arquitetura; a navegação do produto é simples e não sofre dores reais; grande parte do fluxo ainda depende de Fragment ou XML. Esse tipo de análise é parecido com a discussão de Kotlin vs Java em 2026: a melhor tecnologia não existe no vácuo, e sim dentro do custo de adoção do seu time.\nOverlays, resultados e experiências modernas Um dos pontos que mais chamam atenção no Navigation 3 é a evolução para cenas e overlays. Isso abre espaço para lidar melhor com dialogs, folhas modais e fluxos que devolvem resultado para a tela anterior.\nImagine uma tela de perfil que abre um seletor de tema como overlay. Em vez de improvisar estados espalhados pela UI, você consegue tratar isso como parte da navegação.\nUm modelo simplificado seria algo assim:\n@Serializable data class EditorPerfil(val userId: String) @Serializable object SeletorTema Com isso, você consegue representar na pilha algo como:\nHome Perfil(\u0026quot;42\u0026quot;) SeletorTema Essa clareza ajuda muito em debug, analytics e restauração de estado. Se você já se interessa por instrumentação, aproveite também nosso conteúdo sobre observabilidade em Kotlin e Tracy para observabilidade de IA, porque navegação bem modelada também melhora rastreabilidade de eventos.\nPredictive back e UX Android moderna O Android moderno está cada vez mais orientado a gestos, e o predictive back ganhou relevância real em apps que se preocupam com experiência refinada. O Navigation 3 conversa melhor com esse cenário porque sua pilha de navegação é explícita.\nNa prática, isso traz benefícios como:\ncomportamento de retorno mais previsível; integração mais clara com o ciclo de navegação; menos gambiarra para sincronizar estado de tela e gesto do sistema. Esse detalhe importa bastante em apps com múltiplos níveis de profundidade, filtros, painéis laterais e telas com overlays.\nBoas práticas para adotar Navigation 3 Se você resolver experimentar em produção, siga estas recomendações:\n1. Comece por um fluxo isolado Não tente reescrever o app inteiro de uma vez. Pilote numa feature nova, como onboarding, área autenticada ou detalhes de conteúdo.\n2. Modele destinos com tipos pequenos Evite colocar objetos gigantes na chave. Prefira IDs, slugs ou parâmetros mínimos.\n3. Deixe a regra de negócio fora da navegação Navegação deve descrever fluxo de tela, não carregar lógica de domínio. Para isso, use ViewModels, casos de uso e camadas que você já conhece de Clean Architecture em Kotlin.\n4. Teste a serialização Se a chave for serializável, valide cenários de restauração de processo e retomada de estado.\n5. Observe o custo de migração Em apps legados, às vezes o maior ganho está em melhorar a arquitetura ao redor primeiro, e só depois trocar a navegação.\nExemplo de integração com ViewModel Um padrão comum é deixar o ViewModel emitir eventos que alteram a pilha:\nclass HomeViewModel : ViewModel() { private val _eventos = MutableSharedFlow\u0026lt;HomeEvent\u0026gt;() val eventos = _eventos.asSharedFlow() fun abrirArtigo(slug: String) { viewModelScope.launch { _eventos.emit(HomeEvent.AbrirArtigo(slug)) } } } sealed interface HomeEvent { data class AbrirArtigo(val slug: String) : HomeEvent } E na tela:\nLaunchedEffect(Unit) { viewModel.eventos.collect { evento -\u0026gt; when (evento) { is HomeEvent.AbrirArtigo -\u0026gt; backStack.add(DetalheArtigo(evento.slug)) } } } Esse estilo mantém a UI declarativa e ainda preserva uma fronteira clara entre intenção do usuário e mudança de navegação.\nVale a pena estudar Navigation 3 agora? Sim, especialmente se você trabalha com Android moderno, Compose e arquitetura orientada a estado. Mesmo que seu time ainda não migre imediatamente, entender o Navigation 3 ajuda a enxergar melhor para onde o ecossistema Jetpack está caminhando.\nPara quem está começando um app novo em 2026, ele já é uma alternativa muito plausível. Para apps maduros, a adoção precisa ser estratégica, mas faz sentido acompanhar desde já.\nNo fim, o maior valor do Navigation 3 não é apenas “navegar entre telas”. É permitir que a navegação deixe de ser uma camada especial e passe a ser tratada como parte legítima do estado da sua interface.\nPerguntas Frequentes Navigation 3 substitui automaticamente o Navigation Compose tradicional? Não. As duas abordagens podem coexistir no ecossistema. O Navigation 3 é uma biblioteca nova, mais alinhada com Compose-first e modelagem por estado, mas a decisão de migração depende do contexto do projeto.\nPreciso usar serialização com Navigation 3? Na maioria dos exemplos modernos, sim. O padrão mais comum é modelar destinos com tipos serializáveis, o que melhora restauração de estado e segurança de navegação.\nNavigation 3 serve para apps com Fragment? O foco principal é Compose. Em apps fortemente baseados em Fragment, a adoção tende a fazer menos sentido, principalmente se a base atual já estiver estável.\nVale usar Navigation 3 em app novo? Para apps novos, 100% Compose e com equipe confortável com arquitetura declarativa, sim. É justamente onde a biblioteca tende a entregar o maior benefício.\nComo estudar mais navegação e arquitetura Android com Kotlin? Além da documentação oficial, vale aprofundar em Jetpack Compose, MVVM com Kotlin, coroutines e Flow, porque esses conceitos se conectam diretamente com o modelo do Navigation 3. Para quem também desenvolve apps multiplataforma, é interessante comparar como a navegação funciona em outras stacks — como Rust com frameworks como Dioxus aborda UI declarativa e navegação tipada.\n","permalink":"https://kotlin.dev.br/blog/navigation-3-compose-android-2026/","summary":"\u003cp\u003eSe você desenvolve apps Android com Compose, 2026 trouxe uma mudança importante: o \u003cstrong\u003eNavigation 3\u003c/strong\u003e saiu do campo de curiosidade para virar uma opção real de arquitetura. A proposta é simples de entender, mas poderosa na prática: tratar navegação como \u003cstrong\u003eestado da UI\u003c/strong\u003e, com back stack tipada, integração melhor com Compose e APIs mais modernas para transições, overlays e predictive back.\u003c/p\u003e\n\u003cp\u003eNeste guia, você vai entender o que é o Navigation 3, quando ele faz sentido, como configurar o projeto e como montar um fluxo de navegação idiomático em Kotlin. A ideia aqui não é hype. É mostrar onde essa biblioteca realmente ajuda, especialmente em apps novos ou em times que já abraçaram Compose por completo.\u003c/p\u003e","title":"Navigation 3 com Compose: Guia da Nova Navegação Android | Kotlin Brasil"},{"content":"Uma das features mais pedidas pela comunidade Kotlin finalmente está tomando forma. No Kotlin 2.4.0-Beta2, lançado em 22 de abril de 2026, a JetBrains introduziu os collection literals — uma nova sintaxe experimental que permite criar coleções usando colchetes [], similar ao que você já conhece em Python, JavaScript ou Swift.\nSe você acompanhou as novidades do Kotlin 2.4.0 Beta, sabe que essa release veio carregada. Mas os collection literals são, na opinião de muitos devs, a mudança mais impactante no dia a dia de quem escreve Kotlin.\nO problema que os collection literals resolvem Hoje, para criar uma lista simples em Kotlin, você usa listOf():\nval frutas = listOf(\u0026#34;maçã\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;laranja\u0026#34;) val numeros = mutableListOf(1, 2, 3, 4, 5) val mapa = mapOf(\u0026#34;chave\u0026#34; to \u0026#34;valor\u0026#34;, \u0026#34;nome\u0026#34; to \u0026#34;Kotlin\u0026#34;) Funciona bem, mas é verboso comparado a outras linguagens. Em Python, seria [\u0026quot;maçã\u0026quot;, \u0026quot;banana\u0026quot;, \u0026quot;laranja\u0026quot;]. Em JavaScript, a mesma coisa. O Kotlin sempre priorizou concisão — veja as data classes, scope functions e lambdas — e os collection literals seguem essa filosofia.\nA nova sintaxe com colchetes Com collection literals habilitados, a mesma lista fica assim:\nval frutas = [\u0026#34;maçã\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;laranja\u0026#34;] val numeros = [1, 2, 3, 4, 5] Simples, limpo e direto. O compilador infere o tipo automaticamente — no caso acima, List\u0026lt;String\u0026gt; e List\u0026lt;Int\u0026gt;, respectivamente.\nTipo padrão é List (imutável) Quando você cria um literal sem declarar o tipo, o Kotlin infere como List imutável:\nval cores = [\u0026#34;vermelho\u0026#34;, \u0026#34;azul\u0026#34;, \u0026#34;verde\u0026#34;] // Tipo inferido: List\u0026lt;String\u0026gt; Para criar uma lista mutável, declare o tipo explicitamente:\nval coresMutaveis: MutableList\u0026lt;String\u0026gt; = [\u0026#34;vermelho\u0026#34;, \u0026#34;azul\u0026#34;, \u0026#34;verde\u0026#34;] coresMutaveis.add(\u0026#34;amarelo\u0026#34;) // Funciona! Isso é consistente com a filosofia do Kotlin de preferir imutabilidade por padrão — se você quer algo mutável, precisa ser explícito.\nUsando com tipos específicos Você pode declarar o tipo desejado e o compilador se adapta:\nval listaImutavel: List\u0026lt;Int\u0026gt; = [1, 2, 3] val listaMutavel: MutableList\u0026lt;Int\u0026gt; = [1, 2, 3] val conjunto: Set\u0026lt;String\u0026gt; = [\u0026#34;kotlin\u0026#34;, \u0026#34;java\u0026#34;, \u0026#34;scala\u0026#34;] val conjuntoMutavel: MutableSet\u0026lt;String\u0026gt; = [\u0026#34;kotlin\u0026#34;, \u0026#34;java\u0026#34;] Note que a sintaxe [] funciona para List, MutableList, Set e MutableSet. Para mapas, a sintaxe é um pouco diferente — veremos adiante.\nCollection literals em parâmetros de função Onde os collection literals realmente brilham é em chamadas de função. Compare o antes e depois:\nAntes (Kotlin atual) fun processarPedido(itens: List\u0026lt;String\u0026gt;, prioridades: Set\u0026lt;Int\u0026gt;) { // lógica } processarPedido( itens = listOf(\u0026#34;Notebook\u0026#34;, \u0026#34;Mouse\u0026#34;, \u0026#34;Teclado\u0026#34;), prioridades = setOf(1, 2, 3) ) Depois (com collection literals) processarPedido( itens = [\u0026#34;Notebook\u0026#34;, \u0026#34;Mouse\u0026#34;, \u0026#34;Teclado\u0026#34;], prioridades = [1, 2, 3] // inferido como Set\u0026lt;Int\u0026gt; pelo tipo do parâmetro ) O compilador usa o tipo do parâmetro da função para decidir se deve criar uma List ou um Set. Isso elimina a necessidade de chamar listOf() ou setOf() em toda chamada de função.\nEsse pattern fica especialmente útil em DSLs e configurações com Kotlin DSL no Gradle, onde listas de dependências e configurações são comuns.\nCollection literals e annotations Uma área onde collection literals fazem diferença imediata é em annotations:\n@Suppress([\u0026#34;UNCHECKED_CAST\u0026#34;, \u0026#34;DEPRECATION\u0026#34;]) fun minhaFuncao() { // ... } @Target([AnnotationTarget.CLASS, AnnotationTarget.FUNCTION]) annotation class MinhaAnnotation Até agora, o Kotlin usava arrayOf() em annotations — os collection literals oferecem uma alternativa mais limpa.\nCombinando com outras features do Kotlin Com when expressions Os collection literals combinam naturalmente com o when do Kotlin:\nfun classificarFruta(fruta: String): String = when (fruta) { in [\u0026#34;maçã\u0026#34;, \u0026#34;pera\u0026#34;, \u0026#34;uva\u0026#34;] -\u0026gt; \u0026#34;Fruta temperada\u0026#34; in [\u0026#34;manga\u0026#34;, \u0026#34;abacaxi\u0026#34;, \u0026#34;mamão\u0026#34;] -\u0026gt; \u0026#34;Fruta tropical\u0026#34; in [\u0026#34;morango\u0026#34;, \u0026#34;framboesa\u0026#34;, \u0026#34;mirtilo\u0026#34;] -\u0026gt; \u0026#34;Fruta vermelha\u0026#34; else -\u0026gt; \u0026#34;Fruta desconhecida\u0026#34; } Com destructuring Combinado com destructuring, fica ainda mais expressivo:\nval (primeiro, segundo, terceiro) = [\u0026#34;Kotlin\u0026#34;, \u0026#34;Java\u0026#34;, \u0026#34;Scala\u0026#34;] println(\u0026#34;Preferida: $primeiro\u0026#34;) // Preferida: Kotlin Com higher-order functions A integração com higher-order functions e o ecossistema de collections é natural:\nval resultado = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] .filter { it % 2 == 0 } .map { it * it } .sum() println(resultado) // 220 Como habilitar collection literals Como essa feature é experimental no Kotlin 2.4.0-Beta2, você precisa habilitar explicitamente. Adicione no build.gradle.kts:\nkotlin { compilerOptions { freeCompilerArgs.add(\u0026#34;-Xsupport-collection-literals\u0026#34;) } } Ou, se preferir habilitar por arquivo, use a annotation:\n@file:OptIn(ExperimentalCollectionLiterals::class) Lembre-se: como é experimental, a API pode mudar até atingir o status estável. Para projetos em produção, avalie o risco. Para projetos pessoais e protótipos, vale experimentar desde já.\nSe você usa Gradle Version Catalogs no projeto, atualize a versão do Kotlin no libs.versions.toml:\n[versions] kotlin = \u0026#34;2.4.0-Beta2\u0026#34; Impacto na legibilidade do código Vamos comparar um cenário mais realista — configuração de um cliente HTTP com Ktor:\nAntes val config = HttpClientConfig( headers = mapOf( \u0026#34;Content-Type\u0026#34; to \u0026#34;application/json\u0026#34;, \u0026#34;Accept\u0026#34; to \u0026#34;application/json\u0026#34; ), retryStatusCodes = listOf(503, 429, 502), allowedMethods = setOf(\u0026#34;GET\u0026#34;, \u0026#34;POST\u0026#34;, \u0026#34;PUT\u0026#34;, \u0026#34;DELETE\u0026#34;) ) Depois val config = HttpClientConfig( headers = mapOf( \u0026#34;Content-Type\u0026#34; to \u0026#34;application/json\u0026#34;, \u0026#34;Accept\u0026#34; to \u0026#34;application/json\u0026#34; ), retryStatusCodes = [503, 429, 502], allowedMethods = [\u0026#34;GET\u0026#34;, \u0026#34;POST\u0026#34;, \u0026#34;PUT\u0026#34;, \u0026#34;DELETE\u0026#34;] ) A diferença parece sutil em exemplos pequenos, mas em bases de código grandes — especialmente em testes unitários com muitos dados de entrada — a economia de digitação e a clareza visual são significativas.\nO que ainda falta Apesar do avanço, alguns pontos ainda estão em discussão pela equipe do Kotlin:\nMap literals: ainda não há sintaxe literal para mapas. Você continua usando mapOf(\u0026quot;chave\u0026quot; to \u0026quot;valor\u0026quot;). A comunidade está debatendo opções como [\u0026quot;chave\u0026quot;: \u0026quot;valor\u0026quot;] ou {\u0026quot;chave\u0026quot;: \u0026quot;valor\u0026quot;} Array literals: a sintaxe atual não cobre arrays primitivos (IntArray, ByteArray, etc.) Inferência em contextos complexos: em alguns cenários com generics avançados, a inferência pode exigir type annotations explícitas Collection literals vs. outras linguagens Linguagem Lista Mapa Kotlin (novo) [1, 2, 3] mapOf(1 to \u0026quot;a\u0026quot;) Python [1, 2, 3] {1: \u0026quot;a\u0026quot;} Swift [1, 2, 3] [1: \u0026quot;a\u0026quot;] JavaScript [1, 2, 3] {1: \u0026quot;a\u0026quot;} Java List.of(1, 2, 3) Map.of(1, \u0026quot;a\u0026quot;) O Kotlin está se alinhando com a sintaxe que desenvolvedores de outras linguagens já conhecem, reduzindo a curva de aprendizado. Se você veio do Python ou JavaScript e está aprendendo Kotlin, essa sintaxe vai parecer familiar.\nQuando usar e quando evitar Use collection literals quando:\nCriar listas/sets inline em chamadas de função Escrever testes com dados de exemplo Configurar DSLs e builders Inicializar constantes simples Evite por enquanto quando:\nO projeto precisa de estabilidade máxima (ainda é experimental) Você precisa de arrays primitivos para performance O time ainda não está no Kotlin 2.4+ Conclusão Os collection literals são uma adição natural e bem-vinda ao Kotlin. A sintaxe com colchetes é mais concisa, mais familiar para quem vem de outras linguagens, e se integra perfeitamente com o sistema de tipos do Kotlin. Se você já programa em Python, vai notar que a sintaxe [1, 2, 3] é praticamente idêntica — e essa familiaridade é intencional.\nMesmo sendo experimental, vale a pena começar a experimentar em projetos pessoais e acompanhar a evolução para a versão estável. Com o Kotlin 2.4.0 trazendo também context parameters estáveis, explicit backing fields e melhorias no Kotlin/Wasm, o ecossistema continua evoluindo em ritmo forte.\nSe você está começando com Kotlin, confira nosso guia completo e o tutorial de variáveis e tipos para entender a base antes de mergulhar em features avançadas. E para ficar por dentro de todas as novidades, acompanhe nosso blog e a seção de tendências Kotlin 2026.\nPerguntas Frequentes Os collection literals já podem ser usados em produção? Não, os collection literals ainda são experimentais no Kotlin 2.4.0-Beta2. A API pode mudar antes de atingir o status estável. Use em projetos pessoais e protótipos por enquanto, e aguarde a estabilização antes de adotar em produção.\nQual a diferença entre [1, 2, 3] e listOf(1, 2, 3)? Funcionalmente, nenhuma. O compilador traduz [1, 2, 3] para o mesmo bytecode que listOf(1, 2, 3). A diferença é puramente sintática — os collection literals oferecem uma escrita mais concisa e familiar.\nPosso criar mapas com collection literals? Ainda não. Na versão atual, os collection literals suportam List, MutableList, Set e MutableSet. A sintaxe para mapas ainda está sendo discutida pela equipe do Kotlin. Por enquanto, continue usando mapOf().\nPreciso atualizar o Kotlin para usar collection literals? Sim, você precisa do Kotlin 2.4.0-Beta2 ou superior e habilitar a flag experimental -Xsupport-collection-literals no compilador. Também funciona com a annotation @file:OptIn(ExperimentalCollectionLiterals::class) por arquivo.\n","permalink":"https://kotlin.dev.br/blog/collection-literals-kotlin-2026/","summary":"\u003cp\u003eUma das features mais pedidas pela comunidade Kotlin finalmente está tomando forma. No \u003cstrong\u003eKotlin 2.4.0-Beta2\u003c/strong\u003e, lançado em 22 de abril de 2026, a JetBrains introduziu os \u003cstrong\u003ecollection literals\u003c/strong\u003e — uma nova sintaxe experimental que permite criar \u003ca href=\"/glossario/collections/\"\u003ecoleções\u003c/a\u003e usando colchetes \u003ccode\u003e[]\u003c/code\u003e, similar ao que você já conhece em Python, JavaScript ou Swift.\u003c/p\u003e\n\u003cp\u003eSe você acompanhou as \u003ca href=\"/blog/kotlin-2-4-0-beta-novidades-2026/\"\u003enovidades do Kotlin 2.4.0 Beta\u003c/a\u003e, sabe que essa release veio carregada. Mas os collection literals são, na opinião de muitos devs, a mudança mais impactante no dia a dia de quem escreve Kotlin.\u003c/p\u003e","title":"Collection Literals no Kotlin: Nova Sintaxe com Colchetes | Kotlin Brasil"},{"content":"Se você desenvolve com Jetpack Compose ou Compose Multiplatform, já sabe como pode ser frustrante esperar o rebuild completo da aplicação só para ver uma mudança de padding ou cor. Com o lançamento do Compose Hot Reload 1.0.0 — agora estável e empacotado no Compose Multiplatform 1.10 — esse problema acabou. Você edita o código, salva, e a UI atualiza em tempo real, sem reiniciar o app.\nNeste artigo, vamos explorar como funciona, como configurar no seu projeto, e dicas práticas para extrair o máximo dessa ferramenta.\nO que é o Compose Hot Reload? O Compose Hot Reload permite que você edite código de composables e funções e veja o resultado imediatamente na aplicação em execução. Não é um preview isolado — é o app real rodando com todas as dependências, estado e dados, atualizando em tempo real conforme você salva o código.\nDiferente do Live Edit do Android Studio, o Compose Hot Reload funciona em desktop com Compose Multiplatform e usa uma tecnologia mais robusta por baixo dos panos: o DCEVM (Dynamic Code Evolution Virtual Machine) do JetBrains Runtime.\nSe você já usa Compose Multiplatform para desktop ou está planejando migrar, essa feature muda completamente o fluxo de desenvolvimento.\nComo funciona por baixo dos panos A mágica acontece em três etapas:\nVerificação: quando você salva o arquivo, o runtime valida os novos .class compilados para garantir compatibilidade Carregamento: as classes são carregadas em um \u0026ldquo;universo paralelo\u0026rdquo; que representa o estado pós-reload Transferência de estado: um passo especializado de garbage collection migra objetos existentes para acomodar as novas definições de classes O diferencial do DCEVM em relação à JVM padrão é que ele permite mudanças muito mais amplas — incluindo adicionar classes novas, modificar propriedades e remover funções — não apenas alterar o corpo de métodos existentes.\nO sistema usa um mecanismo de hot vs. cold classpath: dependências remotas (bibliotecas, SDKs) ficam estáticas, enquanto o código compilado localmente é atualizado dinamicamente. Checksums são mantidos para detectar mudanças de forma eficiente.\nRequisitos Antes de começar, verifique se seu ambiente atende aos requisitos:\nRequisito Versão mínima Kotlin 2.1.20+ Compose Multiplatform 1.10.0+ JVM Target Java 21 ou anterior Runtime JetBrains Runtime (JBR) IDE IntelliJ IDEA 2025.2.2+ ou Android Studio Otter 2025.2.1+ Se você ainda não conhece as novidades do Kotlin 2.3.20 ou do Kotlin 2.4.0 Beta, vale se atualizar — ambas as versões funcionam perfeitamente com o Hot Reload.\nConfigurando em um projeto novo Se você está criando um projeto novo no IntelliJ IDEA, o setup é automático:\nFile → New → Project → Kotlin Multiplatform Selecione o target Desktop Pronto — o Compose Hot Reload já vem habilitado Nenhuma configuração adicional necessária. O plugin Gradle é adicionado automaticamente quando o projeto inclui um target desktop.\nConfigurando em um projeto existente Se você tem um projeto Compose Multiplatform anterior à versão 1.10, adicione manualmente:\n1. Adicione ao gradle/libs.versions.toml [plugins] composeHotReload = { id = \u0026#34;org.jetbrains.compose.hot-reload\u0026#34;, version.ref = \u0026#34;composeHotReload\u0026#34; } 2. No build.gradle.kts do projeto raiz plugins { alias(libs.plugins.composeHotReload) apply false } 3. No build.gradle.kts do módulo plugins { alias(libs.plugins.composeHotReload) } 4. Adicione ao settings.gradle.kts plugins { id(\u0026#34;org.gradle.toolchains.foojay-resolver-convention\u0026#34;) version \u0026#34;1.0.0\u0026#34; } Se você ainda usa Groovy no Gradle, vale considerar migrar para o Kotlin DSL — o suporte ao Hot Reload é mais fluido. Confira nosso tutorial de Gradle com Kotlin para detalhes.\nUsando na prática Executando o app No seu main.kt, configure a janela com alwaysOnTop = true para manter o app visível enquanto edita:\nfun main() = application { Window( onCloseRequest = ::exitApplication, alwaysOnTop = true, title = \u0026#34;Meu App Kotlin\u0026#34;, ) { App() } } Para iniciar com Hot Reload, você tem duas opções:\nVia IDE: clique no ícone de Run no gutter e selecione \u0026ldquo;Run with Compose Hot Reload\u0026rdquo;\nVia terminal:\n./gradlew :myApp:hotRunJvm Editando e recarregando O fluxo é simples:\nFaça suas alterações em qualquer composable Salve o arquivo (⌘S no macOS, Ctrl+S no Linux/Windows) A UI atualiza automaticamente Veja um exemplo prático. Suponha que você tem este composable:\n@Composable fun CartaoUsuario(nome: String) { Card( modifier = Modifier .fillMaxWidth() .padding(16.dp), elevation = CardDefaults.cardElevation(4.dp) ) { Column(modifier = Modifier.padding(16.dp)) { Text( text = \u0026#34;Olá, $nome!\u0026#34;, style = MaterialTheme.typography.headlineMedium ) Spacer(modifier = Modifier.height(8.dp)) Text( text = \u0026#34;Bem-vindo ao app\u0026#34;, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurfaceVariant ) } } } Agora mude o padding, a cor, adicione um ícone — salve e veja a mudança instantaneamente no app em execução. Sem rebuild, sem reinício.\nA toolbar flutuante Quando o app está rodando com Hot Reload, uma toolbar flutuante aparece no canto da janela mostrando:\nStatus do reload: se está compilando, carregando ou pronto Logs: mensagens de depuração do processo de reload Controle manual: botão para forçar reload quando necessário Se houver erro de compilação, ele aparece diretamente na janela do app — sem precisar voltar para a IDE para ver o stacktrace.\nPreservação de estado Uma das maiores vantagens do Hot Reload sobre simplesmente reiniciar o app é a preservação de estado. Variáveis de estado em remember e mutableStateOf são preservadas entre reloads, desde que a estrutura do composable permaneça compatível.\n@Composable fun Contador() { var contagem by remember { mutableStateOf(0) } Column(horizontalAlignment = Alignment.CenterHorizontally) { Text(\u0026#34;Contagem: $contagem\u0026#34;, style = MaterialTheme.typography.displaySmall) Spacer(modifier = Modifier.height(16.dp)) Button(onClick = { contagem++ }) { Text(\u0026#34;Incrementar\u0026#34;) } } } Se você incrementar o contador para 15 e depois mudar o texto do botão de \u0026ldquo;Incrementar\u0026rdquo; para \u0026ldquo;Adicionar +1\u0026rdquo;, ao salvar o valor 15 será preservado. Isso é essencial para testar estados complexos — como formulários preenchidos ou listas com scroll — sem perder o progresso.\nLimitações atuais Apesar de estável, o Compose Hot Reload tem algumas limitações que você precisa conhecer:\nApenas desktop por enquanto: suporte a Android e iOS está sendo explorado, mas ainda não disponível Java 21 ou anterior: projetos que usam Java 22+ precisam ajustar o target JetBrains Runtime obrigatório: não funciona com OpenJDK ou Oracle JDK padrão Mudanças estruturais profundas: alterações muito grandes (como renomear packages inteiros) podem exigir restart Para projetos Android, o Live Edit no Android Studio continua sendo a alternativa. Mas se você usa Kotlin Multiplatform com target desktop, o Hot Reload é significativamente superior.\nCompose Hot Reload vs. Live Edit vs. Preview Feature Hot Reload Live Edit Compose Preview App real rodando ✅ ✅ ❌ Preserva estado ✅ Parcial ❌ Sem restart ✅ ✅ ✅ Desktop ✅ ❌ ✅ Android ❌ ✅ ✅ Mudanças estruturais ✅ Limitado ✅ Dicas para produtividade máxima Use alwaysOnTop = true na janela para manter o app visível ao lado da IDE Organize composables pequenos — mudanças em funções menores recarregam mais rápido Aproveite a preservação de estado para testar edge cases sem recriar o cenário Combine com Kotlin DSL para criar UIs declarativas que são fáceis de iterar Use scope functions como apply e also para configurações rápidas durante experimentação Conclusão O Compose Hot Reload 1.0 é um marco para o desenvolvimento com Kotlin e Compose. A capacidade de ver mudanças em tempo real, sem perder estado, transforma completamente o fluxo de trabalho — especialmente para quem desenvolve apps desktop com Compose Multiplatform.\nSe você ainda não experimentou, o setup é trivial para projetos novos e simples para projetos existentes. Com o Kotlin 2.4.0 chegando com context parameters estáveis e collection literals, o ecossistema Kotlin nunca esteve tão produtivo.\nPara aprender mais sobre Compose, confira nosso guia completo de Jetpack Compose e o tutorial básico. Se você também trabalha com desenvolvimento nativo de alta performance, vale conhecer como Rust e Zig abordam hot reload e build incremental em seus ecossistemas.\nPerguntas Frequentes O Compose Hot Reload funciona no Android? Não, atualmente o Compose Hot Reload 1.0 funciona apenas em targets desktop (JVM). Para Android, use o Live Edit do Android Studio. A JetBrains está explorando suporte a outras plataformas em versões futuras.\nPreciso de alguma configuração especial para usar? Se seu projeto usa Compose Multiplatform 1.10+ com target desktop, o Hot Reload já vem habilitado automaticamente. Para projetos mais antigos, basta adicionar o plugin Gradle org.jetbrains.compose.hot-reload e sincronizar.\nO estado da aplicação é preservado durante o reload? Sim, variáveis em remember e mutableStateOf são preservadas entre reloads, desde que a estrutura do composable permaneça compatível. Isso permite testar mudanças visuais sem perder dados como formulários preenchidos ou posição de scroll.\nQual a diferença entre Hot Reload e Compose Preview? O Hot Reload atualiza o app real em execução com todas as dependências e estado, enquanto o Preview renderiza composables isoladamente. O Hot Reload preserva estado entre edições e suporta mudanças estruturais mais amplas, como adicionar novas classes.\n","permalink":"https://kotlin.dev.br/blog/compose-hot-reload-kotlin-2026/","summary":"\u003cp\u003eSe você desenvolve com Jetpack Compose ou Compose Multiplatform, já sabe como pode ser frustrante esperar o rebuild completo da aplicação só para ver uma mudança de padding ou cor. Com o lançamento do \u003cstrong\u003eCompose Hot Reload 1.0.0\u003c/strong\u003e — agora estável e empacotado no \u003ca href=\"/blog/compose-multiplatform-1-10-6-2026/\"\u003eCompose Multiplatform 1.10\u003c/a\u003e — esse problema acabou. Você edita o código, salva, e a UI atualiza em tempo real, sem reiniciar o app.\u003c/p\u003e\n\u003cp\u003eNeste artigo, vamos explorar como funciona, como configurar no seu projeto, e dicas práticas para extrair o máximo dessa ferramenta.\u003c/p\u003e","title":"Compose Hot Reload 1.0: Recarregamento em Tempo Real no Kotlin | Kotlin Brasil"},{"content":"Sobre a vagaA Tempo Software busca uma pessoa Analista de QA para atuar na área de Growth em modelo remoto a partir da Argentina.\nSenioridadeNível pleno.\nStack e ferramentas mencionadasCypress, Playwright e Jest para testes e automação.OWASP ZAP para testes de segurança.Java, Kotlin, TypeScript, Python e Go.Jira, Linux e AWS.ObservaçõesA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos ou benefícios.\n","permalink":"https://kotlin.dev.br/vagas/t2fpar908qqu4vjb-tempo-software-analista-de-qa-growth/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Tempo Software busca uma pessoa \u003cstrong\u003eAnalista de QA\u003c/strong\u003e para atuar na área de Growth em modelo remoto a partir da Argentina.\u003c/p\u003e\u003ch3\u003eSenioridade\u003c/h3\u003e\u003cp\u003eNível pleno.\u003c/p\u003e\u003ch3\u003eStack e ferramentas mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eCypress, Playwright e Jest para testes e automação.\u003c/li\u003e\u003cli\u003eOWASP ZAP para testes de segurança.\u003c/li\u003e\u003cli\u003eJava, Kotlin, TypeScript, Python e Go.\u003c/li\u003e\u003cli\u003eJira, Linux e AWS.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eObservações\u003c/h3\u003e\u003cp\u003eA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos ou benefícios.\u003c/p\u003e","title":"Analista de QA (Growth)"},{"content":"Sobre a vagaA PPRO busca uma pessoa em nível júnior para atuar como Engenheiro(a) Associado(a) de Operações Técnicas em modelo híbrido em São Paulo.\nA posição envolve suporte a ambientes técnicos, observabilidade, resposta a incidentes e automação usando ferramentas modernas de cloud e infraestrutura.\nResponsabilidadesApoiar a operação e a confiabilidade de sistemas em produção.Monitorar serviços, investigar alertas e acompanhar incidentes com ferramentas como Datadog e PagerDuty.Colaborar com times de engenharia usando JIRA e fluxos de trabalho técnicos.Contribuir com automações e scripts usando Bash, Python, Java ou Kotlin.Trabalhar com infraestrutura e pipelines envolvendo AWS, Kubernetes, Docker, Terraform, Terragrunt e GitHub Actions.RequisitosInteresse em operações técnicas, infraestrutura, suporte a produção e confiabilidade de sistemas.Conhecimento inicial em AWS e serviços como SQS, SNS ou Kinesis.Familiaridade com Kubernetes, Docker e conceitos de infraestrutura como código.Noções de programação ou scripting com Kotlin, Java, Python ou Bash.Disponibilidade para atuar em modelo híbrido em São Paulo.TecnologiasAWS, Kubernetes, Docker, Datadog, JIRA, PagerDuty, SQS, SNS, Kinesis, Terraform, Terragrunt, GitHub Actions, Java, Kotlin, Bash e Python.\n","permalink":"https://kotlin.dev.br/vagas/2f4pbdbp8rt8lww0-ppro-engenheiro-a-associado-a-de-operacoes-tecnicas/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA PPRO busca uma pessoa em nível júnior para atuar como Engenheiro(a) Associado(a) de Operações Técnicas em modelo híbrido em São Paulo.\u003c/p\u003e\u003cp\u003eA posição envolve suporte a ambientes técnicos, observabilidade, resposta a incidentes e automação usando ferramentas modernas de cloud e infraestrutura.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eApoiar a operação e a confiabilidade de sistemas em produção.\u003c/li\u003e\u003cli\u003eMonitorar serviços, investigar alertas e acompanhar incidentes com ferramentas como Datadog e PagerDuty.\u003c/li\u003e\u003cli\u003eColaborar com times de engenharia usando JIRA e fluxos de trabalho técnicos.\u003c/li\u003e\u003cli\u003eContribuir com automações e scripts usando Bash, Python, Java ou Kotlin.\u003c/li\u003e\u003cli\u003eTrabalhar com infraestrutura e pipelines envolvendo AWS, Kubernetes, Docker, Terraform, Terragrunt e GitHub Actions.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eInteresse em operações técnicas, infraestrutura, suporte a produção e confiabilidade de sistemas.\u003c/li\u003e\u003cli\u003eConhecimento inicial em AWS e serviços como SQS, SNS ou Kinesis.\u003c/li\u003e\u003cli\u003eFamiliaridade com Kubernetes, Docker e conceitos de infraestrutura como código.\u003c/li\u003e\u003cli\u003eNoções de programação ou scripting com Kotlin, Java, Python ou Bash.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuar em modelo híbrido em São Paulo.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cp\u003eAWS, Kubernetes, Docker, Datadog, JIRA, PagerDuty, SQS, SNS, Kinesis, Terraform, Terragrunt, GitHub Actions, Java, Kotlin, Bash e Python.\u003c/p\u003e","title":"Engenheiro(a) Associado(a) de Operações Técnicas"},{"content":"Sobre a vagaO Mercado Livre busca um(a) Engenheiro(a) de Software Sênior para atuação em modelo híbrido no Brasil.\nStack informadaJavaKotlinGolangRequisitosExperiência em engenharia de software em nível sênior.Vivência com desenvolvimento backend usando Java, Kotlin ou Golang.Disponibilidade para atuação em modelo híbrido no Brasil. ","permalink":"https://kotlin.dev.br/vagas/cdhupmej92pymb0q-mercado-libre-engenheiro-a-de-software-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO Mercado Livre busca um(a) Engenheiro(a) de Software Sênior para atuação em modelo híbrido no Brasil.\u003c/p\u003e\u003ch3\u003eStack informada\u003c/h3\u003e\u003cul\u003e\u003cli\u003eJava\u003c/li\u003e\u003cli\u003eKotlin\u003c/li\u003e\u003cli\u003eGolang\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em engenharia de software em nível sênior.\u003c/li\u003e\u003cli\u003eVivência com desenvolvimento backend usando Java, Kotlin ou Golang.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação em modelo híbrido no Brasil.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Sênior"},{"content":"Quando APIs REST não são suficientes — seja por latência, volume de dados ou comunicação entre microsserviços — o gRPC é a alternativa que mais cresce no ecossistema backend. E a combinação com Kotlin e coroutines torna tudo ainda melhor: serviços assíncronos, streaming nativo com Flow e tipagem forte via Protocol Buffers.\nNeste tutorial, vamos construir um serviço gRPC completo em Kotlin: definição do schema, servidor, cliente e streaming bidirecional.\nO que é gRPC? O gRPC é um framework de chamada remota de procedimentos (RPC) criado pelo Google. Diferente de REST, que usa JSON sobre HTTP/1.1, o gRPC usa Protocol Buffers (protobuf) sobre HTTP/2, trazendo:\nSerialização binária — até 10x mais rápida que JSON Streaming — unidirecional e bidirecional nativamente Geração de código — cliente e servidor gerados a partir de um arquivo .proto Multiplexing — múltiplas requisições sobre uma única conexão TCP Compressão nativa — payloads menores automaticamente Para quem já trabalha com APIs REST em Kotlin, o gRPC é o próximo passo para cenários de alta performance.\nConfigurando o projeto Crie um projeto Kotlin com Gradle e adicione as dependências do gRPC:\n// build.gradle.kts import com.google.protobuf.gradle.* plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.3.20\u0026#34; id(\u0026#34;com.google.protobuf\u0026#34;) version \u0026#34;0.9.4\u0026#34; application } repositories { mavenCentral() } dependencies { // gRPC Kotlin implementation(\u0026#34;io.grpc:grpc-kotlin-stub:1.4.3\u0026#34;) implementation(\u0026#34;io.grpc:grpc-protobuf:1.70.0\u0026#34;) implementation(\u0026#34;io.grpc:grpc-netty-shaded:1.70.0\u0026#34;) // Protobuf implementation(\u0026#34;com.google.protobuf:protobuf-kotlin:4.29.3\u0026#34;) // Coroutines implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1\u0026#34;) // Logging implementation(\u0026#34;ch.qos.logback:logback-classic:1.5.15\u0026#34;) } protobuf { protoc { artifact = \u0026#34;com.google.protobuf:protoc:4.29.3\u0026#34; } plugins { create(\u0026#34;grpc\u0026#34;) { artifact = \u0026#34;io.grpc:protoc-gen-grpc-java:1.70.0\u0026#34; } create(\u0026#34;grpckt\u0026#34;) { artifact = \u0026#34;io.grpc:protoc-gen-grpc-kotlin:1.4.3:jdk8@jar\u0026#34; } } generateProtoTasks { all().forEach { it.plugins { create(\u0026#34;grpc\u0026#34;) create(\u0026#34;grpckt\u0026#34;) } it.builtins { create(\u0026#34;kotlin\u0026#34;) } } } } application { mainClass.set(\u0026#34;com.exemplo.MainKt\u0026#34;) } Se você prefere organizar versões de forma centralizada, confira nosso artigo sobre Gradle Version Catalog em Kotlin — funciona perfeitamente com projetos gRPC.\nDefinindo o serviço com Protocol Buffers Crie o arquivo .proto que define a interface do serviço:\n// src/main/proto/produto.proto syntax = \u0026#34;proto3\u0026#34;; package com.exemplo; option java_multiple_files = true; option java_package = \u0026#34;com.exemplo.grpc\u0026#34;; // Mensagens message ProdutoRequest { string id = 1; } message ProdutoResponse { string id = 1; string nome = 2; double preco = 3; string categoria = 4; int32 estoque = 5; } message ListaProdutosRequest { string categoria = 1; int32 limite = 2; } message CriarProdutoRequest { string nome = 1; double preco = 2; string categoria = 3; int32 estoque = 4; } message AtualizarEstoqueRequest { string id = 1; int32 quantidade = 2; } message EstoqueResponse { string id = 1; int32 estoque_anterior = 2; int32 estoque_atual = 3; } // Serviço service ProdutoService { // Unário: busca um produto por ID rpc BuscarProduto(ProdutoRequest) returns (ProdutoResponse); // Unário: cria um novo produto rpc CriarProduto(CriarProdutoRequest) returns (ProdutoResponse); // Server streaming: lista produtos por categoria rpc ListarProdutos(ListaProdutosRequest) returns (stream ProdutoResponse); // Client streaming: atualiza estoque em lote rpc AtualizarEstoqueLote(stream AtualizarEstoqueRequest) returns (EstoqueResponse); } Ao compilar com ./gradlew generateProto, o plugin gera automaticamente classes Kotlin com suporte a coroutines — métodos suspend para chamadas unárias e Flow para streaming.\nImplementando o servidor Com o código gerado, implemente o serviço estendendo a classe base:\n// src/main/kotlin/com/exemplo/ProdutoServiceImpl.kt package com.exemplo import com.exemplo.grpc.* import io.grpc.Status import io.grpc.StatusException import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow class ProdutoServiceImpl : ProdutoServiceGrpcKt.ProdutoServiceCoroutineImplBase() { // Simulando um banco de dados em memória private val produtos = mutableMapOf( \u0026#34;1\u0026#34; to ProdutoData(\u0026#34;1\u0026#34;, \u0026#34;Teclado Mecânico\u0026#34;, 349.90, \u0026#34;Periféricos\u0026#34;, 50), \u0026#34;2\u0026#34; to ProdutoData(\u0026#34;2\u0026#34;, \u0026#34;Monitor 4K 27\\\u0026#34;\u0026#34;, 2199.00, \u0026#34;Monitores\u0026#34;, 15), \u0026#34;3\u0026#34; to ProdutoData(\u0026#34;3\u0026#34;, \u0026#34;Mouse Gamer\u0026#34;, 189.90, \u0026#34;Periféricos\u0026#34;, 80), \u0026#34;4\u0026#34; to ProdutoData(\u0026#34;4\u0026#34;, \u0026#34;Webcam Full HD\u0026#34;, 299.90, \u0026#34;Periféricos\u0026#34;, 30), \u0026#34;5\u0026#34; to ProdutoData(\u0026#34;5\u0026#34;, \u0026#34;Monitor Ultrawide\u0026#34;, 3499.00, \u0026#34;Monitores\u0026#34;, 8), ) // RPC unário: busca produto por ID override suspend fun buscarProduto(request: ProdutoRequest): ProdutoResponse { val produto = produtos[request.id] ?: throw StatusException( Status.NOT_FOUND.withDescription(\u0026#34;Produto ${request.id} não encontrado\u0026#34;) ) return produto.toResponse() } // RPC unário: cria novo produto override suspend fun criarProduto(request: CriarProdutoRequest): ProdutoResponse { val id = (produtos.size + 1).toString() val novo = ProdutoData( id = id, nome = request.nome, preco = request.preco, categoria = request.categoria, estoque = request.estoque ) produtos[id] = novo return novo.toResponse() } // Server streaming: envia produtos um a um override fun listarProdutos(request: ListaProdutosRequest): Flow\u0026lt;ProdutoResponse\u0026gt; = flow { val filtrados = produtos.values .filter { it.categoria.equals(request.categoria, ignoreCase = true) } .take(if (request.limite \u0026gt; 0) request.limite else Int.MAX_VALUE) for (produto in filtrados) { emit(produto.toResponse()) delay(100) // Simula latência de processamento } } // Client streaming: recebe atualizações em lote override suspend fun atualizarEstoqueLote( requests: Flow\u0026lt;AtualizarEstoqueRequest\u0026gt; ): EstoqueResponse { var totalAtualizado = 0 var ultimoId = \u0026#34;\u0026#34; requests.collect { request -\u0026gt; val produto = produtos[request.id] if (produto != null) { val estoqueAnterior = produto.estoque produto.estoque += request.quantidade totalAtualizado++ ultimoId = request.id } } return estoqueResponse { id = \u0026#34;lote\u0026#34; estoqueAnterior = totalAtualizado estoqueAtual = totalAtualizado } } } // Data class interna data class ProdutoData( val id: String, val nome: String, val preco: Double, val categoria: String, var estoque: Int ) { fun toResponse(): ProdutoResponse = produtoResponse { id = this@ProdutoData.id nome = this@ProdutoData.nome preco = this@ProdutoData.preco categoria = this@ProdutoData.categoria estoque = this@ProdutoData.estoque } } Repare como o método listarProdutos retorna um Flow\u0026lt;ProdutoResponse\u0026gt; — é a integração nativa do gRPC-Kotlin com Kotlin Flow. O servidor emite respostas uma a uma, e o cliente as recebe de forma reativa.\nIniciando o servidor // src/main/kotlin/com/exemplo/Main.kt package com.exemplo import io.grpc.ServerBuilder fun main() { val porta = 50051 val server = ServerBuilder .forPort(porta) .addService(ProdutoServiceImpl()) .build() server.start() println(\u0026#34;Servidor gRPC rodando na porta $porta\u0026#34;) // Graceful shutdown Runtime.getRuntime().addShutdownHook(Thread { println(\u0026#34;Desligando servidor gRPC...\u0026#34;) server.shutdown() }) server.awaitTermination() } Implementando o cliente O cliente também usa coroutines nativamente:\n// src/main/kotlin/com/exemplo/ProdutoClient.kt package com.exemplo import com.exemplo.grpc.* import io.grpc.ManagedChannelBuilder import kotlinx.coroutines.flow.flow import kotlinx.coroutines.runBlocking fun main() = runBlocking { val channel = ManagedChannelBuilder .forAddress(\u0026#34;localhost\u0026#34;, 50051) .usePlaintext() .build() val stub = ProdutoServiceGrpcKt.ProdutoServiceCoroutineStub(channel) // 1. Chamada unária: buscar produto println(\u0026#34;=== Buscar Produto ===\u0026#34;) val produto = stub.buscarProduto(produtoRequest { id = \u0026#34;1\u0026#34; }) println(\u0026#34;Encontrado: ${produto.nome} — R$ ${produto.preco}\u0026#34;) // 2. Chamada unária: criar produto println(\u0026#34;\\n=== Criar Produto ===\u0026#34;) val novo = stub.criarProduto(criarProdutoRequest { nome = \u0026#34;SSD NVMe 1TB\u0026#34; preco = 499.90 categoria = \u0026#34;Armazenamento\u0026#34; estoque = 25 }) println(\u0026#34;Criado: ${novo.nome} (ID: ${novo.id})\u0026#34;) // 3. Server streaming: listar produtos println(\u0026#34;\\n=== Listar Periféricos ===\u0026#34;) stub.listarProdutos(listaProdutosRequest { categoria = \u0026#34;Periféricos\u0026#34; limite = 10 }).collect { p -\u0026gt; println(\u0026#34; → ${p.nome}: R$ ${p.preco} (${p.estoque} em estoque)\u0026#34;) } // 4. Client streaming: atualizar estoque em lote println(\u0026#34;\\n=== Atualizar Estoque em Lote ===\u0026#34;) val atualizacoes = flow { emit(atualizarEstoqueRequest { id = \u0026#34;1\u0026#34;; quantidade = 10 }) emit(atualizarEstoqueRequest { id = \u0026#34;3\u0026#34;; quantidade = -5 }) emit(atualizarEstoqueRequest { id = \u0026#34;4\u0026#34;; quantidade = 20 }) } val resultado = stub.atualizarEstoqueLote(atualizacoes) println(\u0026#34;Itens atualizados: ${resultado.estoqueAtual}\u0026#34;) channel.shutdown() } Perceba que o cliente collect o streaming do servidor da mesma forma que faria com qualquer Flow no Kotlin — sem callbacks, sem listeners, sem boilerplate.\ngRPC vs REST: quando usar cada um A pergunta não é qual é \u0026ldquo;melhor\u0026rdquo;, mas qual se encaixa no cenário:\nCritério REST gRPC Formato JSON (texto) Protobuf (binário) Protocolo HTTP/1.1 ou 2 HTTP/2 obrigatório Streaming SSE, WebSocket Nativo (4 tipos) Geração de código Opcional (OpenAPI) Obrigatória (protoc) Browser Nativo Precisa de gRPC-Web Performance Boa Excelente Ferramentas Postman, curl grpcurl, BloomRPC Use gRPC quando:\nComunicação entre microsserviços internos Alta throughput e baixa latência são críticos Streaming bidirecional é necessário Contratos fortes entre serviços são prioridade Use REST quando:\nAPI pública consumida por browsers Integração com serviços de terceiros Time mais familiarizado com REST Se seu cenário é microsserviços, veja também nosso guia de microsserviços com Kotlin e o artigo sobre Kotlin com Kubernetes.\nTratamento de erros no gRPC O gRPC tem um sistema de status codes próprio. Veja como usar em Kotlin:\nimport io.grpc.Status import io.grpc.StatusException override suspend fun buscarProduto(request: ProdutoRequest): ProdutoResponse { if (request.id.isBlank()) { throw StatusException( Status.INVALID_ARGUMENT.withDescription(\u0026#34;ID não pode ser vazio\u0026#34;) ) } val produto = produtos[request.id] ?: throw StatusException( Status.NOT_FOUND.withDescription(\u0026#34;Produto não encontrado: ${request.id}\u0026#34;) ) return produto.toResponse() } Os códigos mais usados:\nStatus Código Uso OK 0 Sucesso INVALID_ARGUMENT 3 Parâmetros inválidos NOT_FOUND 5 Recurso inexistente ALREADY_EXISTS 6 Duplicata PERMISSION_DENIED 7 Sem permissão INTERNAL 13 Erro interno UNAVAILABLE 14 Serviço temporariamente fora Para quem vem do mundo REST, é similar aos HTTP status codes, mas com semântica mais precisa. Combinado com observabilidade, você monitora cada RPC com métricas detalhadas.\nInterceptors: middleware para gRPC Assim como middleware em REST, interceptors permitem lógica transversal:\nimport io.grpc.* class LoggingInterceptor : ServerInterceptor { override fun \u0026lt;ReqT, RespT\u0026gt; interceptCall( call: ServerCall\u0026lt;ReqT, RespT\u0026gt;, headers: Metadata, next: ServerCallHandler\u0026lt;ReqT, RespT\u0026gt; ): ServerCall.Listener\u0026lt;ReqT\u0026gt; { val metodo = call.methodDescriptor.fullMethodName val inicio = System.currentTimeMillis() println(\u0026#34;→ gRPC chamada: $metodo\u0026#34;) return object : ForwardingServerCallListener.SimpleForwardingServerCallListener\u0026lt;ReqT\u0026gt;( next.startCall(call, headers) ) { override fun onComplete() { val duracao = System.currentTimeMillis() - inicio println(\u0026#34;← gRPC resposta: $metodo (${duracao}ms)\u0026#34;) super.onComplete() } } } } // Registrando no servidor val server = ServerBuilder .forPort(50051) .addService(ServerInterceptors.intercept(ProdutoServiceImpl(), LoggingInterceptor())) .build() Para monitoramento em produção, combine interceptors com OpenTelemetry e Tracy para tracing distribuído completo.\nTestando serviços gRPC Teste seus serviços gRPC com o grpc-testing:\nimport io.grpc.inprocess.InProcessChannelBuilder import io.grpc.inprocess.InProcessServerBuilder import io.grpc.testing.GrpcCleanupRule import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.jupiter.api.Test import kotlin.test.assertEquals class ProdutoServiceTest { @get:Rule val grpcCleanup = GrpcCleanupRule() @Test fun `deve buscar produto existente`() = runTest { val serverName = InProcessServerBuilder.generateName() grpcCleanup.register( InProcessServerBuilder.forName(serverName) .directExecutor() .addService(ProdutoServiceImpl()) .build() .start() ) val channel = grpcCleanup.register( InProcessChannelBuilder.forName(serverName) .directExecutor() .build() ) val stub = ProdutoServiceGrpcKt.ProdutoServiceCoroutineStub(channel) val response = stub.buscarProduto(produtoRequest { id = \u0026#34;1\u0026#34; }) assertEquals(\u0026#34;Teclado Mecânico\u0026#34;, response.nome) assertEquals(349.90, response.preco) } } Usando InProcessServer, os testes rodam sem abrir porta de rede — rápidos e isolados. Se quiser aprofundar em testes, confira nosso guia de testes com JUnit5 e MockK.\nPerguntas Frequentes gRPC funciona com Kotlin Multiplatform? Ainda não de forma oficial. O gRPC-Kotlin roda na JVM (servidor e Android). Para KMP com iOS e Web, alternativas como Ktor Client com serialização protobuf são mais viáveis atualmente.\nPosso usar gRPC com Spring Boot? Sim. O Spring Boot tem suporte via grpc-spring-boot-starter. Você combina a injeção de dependência do Spring com os stubs gRPC gerados.\ngRPC substitui REST completamente? Não. Para APIs públicas consumidas por browsers, REST ainda é o padrão. gRPC brilha na comunicação service-to-service em arquiteturas de microsserviços.\nQual a diferença entre gRPC e Ktor RPC? O Ktor agora oferece o Kotlin RPC — uma alternativa nativa em Kotlin puro, sem protobuf. É mais simples para projetos que já usam Ktor, mas o gRPC tem ecossistema mais maduro e interop com Go, Java, Python, C++.\nComo monitorar serviços gRPC em produção? Use interceptors com OpenTelemetry para tracing distribuído. Combine com observabilidade Kotlin e dashboards como Grafana para métricas de latência, throughput e taxa de erros.\nConclusão O gRPC com Kotlin e coroutines é uma combinação poderosa para serviços backend de alta performance. A geração de código garante contratos fortes, o streaming nativo via Flow simplifica cenários reativos, e a performance do protobuf faz diferença real em produção.\nSe você está começando no backend Kotlin, recomendo primeiro dominar coroutines e Flow antes de mergulhar no gRPC. E para quem já está construindo microsserviços, explore como combinar gRPC com Docker e Kubernetes para uma stack de produção completa.\nVale saber que o gRPC é amplamente usado em Go e Python — se seu time é poliglota, o gRPC permite interoperabilidade nativa entre serviços Kotlin e essas linguagens via protobuf.\nQuer explorar mais sobre o ecossistema? Veja as tendências do Kotlin para 2026 e o roadmap para dev backend.\n","permalink":"https://kotlin.dev.br/blog/grpc-kotlin-coroutines-tutorial-2026/","summary":"\u003cp\u003eQuando APIs REST não são suficientes — seja por latência, volume de dados ou comunicação entre microsserviços — o \u003cstrong\u003egRPC\u003c/strong\u003e é a alternativa que mais cresce no ecossistema backend. E a combinação com \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003ecoroutines\u003c/strong\u003e torna tudo ainda melhor: serviços assíncronos, streaming nativo com \u003ca href=\"/blog/kotlin-flow/\"\u003eFlow\u003c/a\u003e e tipagem forte via Protocol Buffers.\u003c/p\u003e\n\u003cp\u003eNeste tutorial, vamos construir um serviço gRPC completo em Kotlin: definição do schema, servidor, cliente e streaming bidirecional.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-grpc\"\u003eO que é gRPC?\u003c/h2\u003e\n\u003cp\u003eO gRPC é um framework de chamada remota de procedimentos (RPC) criado pelo Google. Diferente de REST, que usa JSON sobre HTTP/1.1, o gRPC usa \u003cstrong\u003eProtocol Buffers\u003c/strong\u003e (protobuf) sobre \u003cstrong\u003eHTTP/2\u003c/strong\u003e, trazendo:\u003c/p\u003e","title":"gRPC com Kotlin e Coroutines: Tutorial Completo | Kotlin Brasil"},{"content":"Se você trabalha com Kotlin — seja no Android, backend com Spring Boot ou Ktor — já deve ter sofrido com gerenciamento de dependências no Gradle. Versões espalhadas por múltiplos build.gradle.kts, conflitos difíceis de rastrear e atualizações manuais em dezenas de módulos.\nO Gradle Version Catalog resolve tudo isso com um único arquivo TOML centralizado. Neste guia prático, você vai aprender a configurar, migrar e dominar essa feature que já virou padrão em projetos Kotlin modernos.\nO que é o Gradle Version Catalog? O Version Catalog é um recurso nativo do Gradle (disponível desde a versão 7.0 e estável desde a 7.4.1) que centraliza todas as dependências, plugins e versões do seu projeto em um arquivo chamado libs.versions.toml.\nEm vez de espalhar versões assim:\n// módulo app/build.gradle.kts dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-core:3.1.1\u0026#34;) } // módulo shared/build.gradle.kts dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1\u0026#34;) // duplicado! } Você declara tudo num lugar só e referencia com type-safe accessors:\n// módulo app/build.gradle.kts dependencies { implementation(libs.kotlinx.coroutines.core) implementation(libs.ktor.server.core) } Se você já leu nosso tutorial de Gradle com Kotlin, o Version Catalog é a evolução natural para projetos com múltiplos módulos.\nCriando o arquivo libs.versions.toml O arquivo fica em gradle/libs.versions.toml na raiz do projeto. O Gradle o detecta automaticamente.\n# gradle/libs.versions.toml [versions] kotlin = \u0026#34;2.3.20\u0026#34; coroutines = \u0026#34;1.10.1\u0026#34; ktor = \u0026#34;3.1.1\u0026#34; exposed = \u0026#34;1.0.0\u0026#34; logback = \u0026#34;1.5.15\u0026#34; junit = \u0026#34;5.11.4\u0026#34; mockk = \u0026#34;1.13.16\u0026#34; [libraries] kotlinx-coroutines-core = { module = \u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core\u0026#34;, version.ref = \u0026#34;coroutines\u0026#34; } kotlinx-coroutines-test = { module = \u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-test\u0026#34;, version.ref = \u0026#34;coroutines\u0026#34; } ktor-server-core = { module = \u0026#34;io.ktor:ktor-server-core\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } ktor-server-netty = { module = \u0026#34;io.ktor:ktor-server-netty\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } ktor-server-content-negotiation = { module = \u0026#34;io.ktor:ktor-server-content-negotiation\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } ktor-serialization-json = { module = \u0026#34;io.ktor:ktor-serialization-kotlinx-json\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } exposed-core = { module = \u0026#34;org.jetbrains.exposed:exposed-core\u0026#34;, version.ref = \u0026#34;exposed\u0026#34; } exposed-dao = { module = \u0026#34;org.jetbrains.exposed:exposed-dao\u0026#34;, version.ref = \u0026#34;exposed\u0026#34; } exposed-jdbc = { module = \u0026#34;org.jetbrains.exposed:exposed-jdbc\u0026#34;, version.ref = \u0026#34;exposed\u0026#34; } logback-classic = { module = \u0026#34;ch.qos.logback:logback-classic\u0026#34;, version.ref = \u0026#34;logback\u0026#34; } junit-jupiter = { module = \u0026#34;org.junit.jupiter:junit-jupiter\u0026#34;, version.ref = \u0026#34;junit\u0026#34; } mockk = { module = \u0026#34;io.mockk:mockk\u0026#34;, version.ref = \u0026#34;mockk\u0026#34; } [bundles] ktor-server = [\u0026#34;ktor-server-core\u0026#34;, \u0026#34;ktor-server-netty\u0026#34;, \u0026#34;ktor-server-content-negotiation\u0026#34;, \u0026#34;ktor-serialization-json\u0026#34;] exposed = [\u0026#34;exposed-core\u0026#34;, \u0026#34;exposed-dao\u0026#34;, \u0026#34;exposed-jdbc\u0026#34;] testing = [\u0026#34;junit-jupiter\u0026#34;, \u0026#34;mockk\u0026#34;, \u0026#34;kotlinx-coroutines-test\u0026#34;] [plugins] kotlin-jvm = { id = \u0026#34;org.jetbrains.kotlin.jvm\u0026#34;, version.ref = \u0026#34;kotlin\u0026#34; } kotlin-serialization = { id = \u0026#34;org.jetbrains.kotlin.plugin.serialization\u0026#34;, version.ref = \u0026#34;kotlin\u0026#34; } ktor = { id = \u0026#34;io.ktor.plugin\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } O arquivo tem quatro seções:\nSeção Propósito [versions] Declara versões reutilizáveis [libraries] Define dependências com referência a versões [bundles] Agrupa dependências relacionadas [plugins] Declara plugins do Gradle Usando no build.gradle.kts Depois de criar o TOML, use os accessors gerados automaticamente:\n// build.gradle.kts (raiz) plugins { alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.ktor) apply false } // app/build.gradle.kts plugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.ktor) alias(libs.plugins.kotlin.serialization) } dependencies { // Usando bundle — adiciona todas as deps do Ktor de uma vez implementation(libs.bundles.ktor.server) // Usando bundle do Exposed implementation(libs.bundles.exposed) // Dependência individual implementation(libs.logback.classic) // Bundle de testes testImplementation(libs.bundles.testing) } Perceba como os bundles simplificam o código. Em vez de listar 4 dependências do Ktor, uma linha resolve. Isso é especialmente útil em projetos multi-módulo — algo que exploramos no artigo sobre monólito modular com Kotlin.\nExemplo prático: projeto Android com Compose Para projetos Android com Jetpack Compose, o Version Catalog brilha ainda mais:\n# gradle/libs.versions.toml [versions] kotlin = \u0026#34;2.3.20\u0026#34; agp = \u0026#34;8.8.2\u0026#34; compose-bom = \u0026#34;2025.03.00\u0026#34; compose-compiler = \u0026#34;2.0.0\u0026#34; lifecycle = \u0026#34;2.8.7\u0026#34; navigation = \u0026#34;2.8.5\u0026#34; hilt = \u0026#34;2.53.1\u0026#34; room = \u0026#34;2.6.1\u0026#34; coroutines = \u0026#34;1.10.1\u0026#34; [libraries] compose-bom = { module = \u0026#34;androidx.compose:compose-bom\u0026#34;, version.ref = \u0026#34;compose-bom\u0026#34; } compose-ui = { module = \u0026#34;androidx.compose.ui:ui\u0026#34; } compose-material3 = { module = \u0026#34;androidx.compose.material3:material3\u0026#34; } compose-tooling-preview = { module = \u0026#34;androidx.compose.ui:ui-tooling-preview\u0026#34; } compose-tooling = { module = \u0026#34;androidx.compose.ui:ui-tooling\u0026#34; } lifecycle-runtime = { module = \u0026#34;androidx.lifecycle:lifecycle-runtime-compose\u0026#34;, version.ref = \u0026#34;lifecycle\u0026#34; } lifecycle-viewmodel = { module = \u0026#34;androidx.lifecycle:lifecycle-viewmodel-compose\u0026#34;, version.ref = \u0026#34;lifecycle\u0026#34; } navigation-compose = { module = \u0026#34;androidx.navigation:navigation-compose\u0026#34;, version.ref = \u0026#34;navigation\u0026#34; } room-runtime = { module = \u0026#34;androidx.room:room-runtime\u0026#34;, version.ref = \u0026#34;room\u0026#34; } room-ktx = { module = \u0026#34;androidx.room:room-ktx\u0026#34;, version.ref = \u0026#34;room\u0026#34; } room-compiler = { module = \u0026#34;androidx.room:room-compiler\u0026#34;, version.ref = \u0026#34;room\u0026#34; } [bundles] compose = [\u0026#34;compose-ui\u0026#34;, \u0026#34;compose-material3\u0026#34;, \u0026#34;compose-tooling-preview\u0026#34;] lifecycle = [\u0026#34;lifecycle-runtime\u0026#34;, \u0026#34;lifecycle-viewmodel\u0026#34;] [plugins] android-application = { id = \u0026#34;com.android.application\u0026#34;, version.ref = \u0026#34;agp\u0026#34; } kotlin-android = { id = \u0026#34;org.jetbrains.kotlin.android\u0026#34;, version.ref = \u0026#34;kotlin\u0026#34; } kotlin-compose = { id = \u0026#34;org.jetbrains.kotlin.plugin.compose\u0026#34;, version.ref = \u0026#34;kotlin\u0026#34; } hilt = { id = \u0026#34;com.google.dagger.hilt.android\u0026#34;, version.ref = \u0026#34;hilt\u0026#34; } E no build.gradle.kts do módulo:\ndependencies { implementation(platform(libs.compose.bom)) implementation(libs.bundles.compose) implementation(libs.bundles.lifecycle) implementation(libs.navigation.compose) implementation(libs.room.runtime) implementation(libs.room.ktx) ksp(libs.room.compiler) debugImplementation(libs.compose.tooling) } Se você está começando com Compose, confira nosso tutorial básico de Jetpack Compose e o guia de layouts no Compose.\nBundles: agrupando dependências Os bundles são uma das features mais úteis. Eles agrupam dependências que sempre andam juntas:\n[bundles] # Tudo que precisa para um server Ktor com JSON ktor-server = [ \u0026#34;ktor-server-core\u0026#34;, \u0026#34;ktor-server-netty\u0026#34;, \u0026#34;ktor-server-content-negotiation\u0026#34;, \u0026#34;ktor-serialization-json\u0026#34; ] # Stack de testes completa testing = [ \u0026#34;junit-jupiter\u0026#34;, \u0026#34;mockk\u0026#34;, \u0026#34;kotlinx-coroutines-test\u0026#34; ] Se você trabalha com testes em Kotlin usando JUnit5 e MockK, criar um bundle de testes evita repetir as mesmas 3-5 dependências em cada módulo.\nMigrando um projeto existente A migração é simples e incremental — você não precisa converter tudo de uma vez:\nPasso 1: Crie o arquivo TOML mkdir -p gradle touch gradle/libs.versions.toml Passo 2: Extraia versões existentes Procure todas as versões hardcoded nos seus build.gradle.kts e mova para o TOML:\n// ANTES — build.gradle.kts dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1\u0026#34;) } // DEPOIS — build.gradle.kts dependencies { implementation(libs.kotlinx.coroutines.core) } Passo 3: Sync e valide ./gradlew build O Gradle gera os accessors automaticamente. Se usar IntelliJ IDEA ou Android Studio, o autocomplete funciona imediatamente.\nPasso 4: Converta módulo por módulo Não precisa migrar todos os módulos de uma vez. O Gradle permite misturar strings com accessors durante a transição.\nBoas práticas Depois de ter configurado diversos projetos Kotlin com Version Catalog, estas são as práticas que mais fazem diferença:\nUse kebab-case nos nomes — ktor-server-core vira libs.ktor.server.core. O Gradle converte automaticamente.\nAgrupe por ecossistema — organize as libraries por família (Ktor, Exposed, Compose, etc.) para facilitar a leitura.\nCrie bundles para stacks recorrentes — se seus módulos sempre usam as mesmas 4 dependências juntas, faça um bundle.\nNão abuse das versões compartilhadas — nem toda dependência precisa de version.ref. Se só uma library usa aquela versão, declare inline: version = \u0026quot;1.0.0\u0026quot;.\nMantenha o TOML atualizado — ferramentas como Renovate e Dependabot já suportam libs.versions.toml.\nDocumente com comentários — o formato TOML aceita # para comentários. Use para explicar por que uma versão está pinada.\nPara mais dicas de organização de projetos, confira nosso guia de Gradle com Kotlin DSL.\nVersion Catalog vs buildSrc vs Convention Plugins É comum a dúvida: quando usar cada abordagem?\nAbordagem Quando usar Version Catalog Centralizar versões e dependências buildSrc Lógica de build compartilhada simples Convention Plugins Configurações de build complexas e reutilizáveis Na prática, a maioria dos projetos modernos combina Version Catalog + Convention Plugins. O catalog cuida das versões, e os convention plugins cuidam da configuração dos módulos.\nSe quiser entender melhor o build system do Kotlin, temos um guia completo de Gradle e um artigo sobre o Amper, o novo build tool da JetBrains.\nPerguntas Frequentes O Version Catalog funciona com Kotlin Multiplatform? Sim, funciona perfeitamente com KMP. Você pode declarar dependências para cada source set (commonMain, androidMain, iosMain) e referenciá-las com os mesmos accessors type-safe.\nPreciso de alguma versão mínima do Gradle? O recurso ficou estável no Gradle 7.4.1. Se você usa Kotlin 2.x, já está em uma versão compatível. Projetos com Kotlin 2.3.20 ou Kotlin 2.4.0 usam Gradle 8.x, que tem suporte completo.\nPosso usar Version Catalog com projetos Spring Boot? Com certeza. O Spring Boot com Kotlin funciona normalmente com Version Catalog. Basta declarar o plugin do Spring e as dependências no TOML.\nO autocomplete funciona no IntelliJ? Sim. Tanto o IntelliJ IDEA quanto o Android Studio oferecem autocomplete completo para os accessors gerados. Confira nosso artigo sobre as melhores IDEs para Kotlin.\nComo atualizar dependências automaticamente? Use Renovate ou Dependabot — ambos já parseiam libs.versions.toml. Combine com CI/CD para validar cada atualização com testes automáticos.\nConclusão O Gradle Version Catalog não é mais uma novidade — é o padrão em projetos Kotlin modernos. Se você ainda gerencia dependências com strings hardcoded, está desperdiçando tempo e acumulando risco de conflitos.\nA migração é simples, incremental e os benefícios aparecem no primeiro dia: menos duplicação, autocomplete, bundles que simplificam módulos e um único lugar para atualizar versões.\nSe você está começando no ecossistema Kotlin, explore nosso guia completo e veja as tendências para 2026. E se está planejando a carreira, confira o roadmap para dev backend Kotlin — dominar o build system é diferencial em entrevistas. Para quem também trabalha com Go, vale comparar como o go.mod resolve o gerenciamento de dependências de forma nativa — cada ecossistema tem sua abordagem, e conhecer várias amplia sua visão como dev.\n","permalink":"https://kotlin.dev.br/blog/gradle-version-catalog-kotlin-2026/","summary":"\u003cp\u003eSe você trabalha com Kotlin — seja no Android, backend com \u003ca href=\"/blog/kotlin-spring-boot/\"\u003eSpring Boot\u003c/a\u003e ou \u003ca href=\"/blog/ktor-criando-apis-kotlin/\"\u003eKtor\u003c/a\u003e — já deve ter sofrido com gerenciamento de dependências no Gradle. Versões espalhadas por múltiplos \u003ccode\u003ebuild.gradle.kts\u003c/code\u003e, conflitos difíceis de rastrear e atualizações manuais em dezenas de módulos.\u003c/p\u003e\n\u003cp\u003eO \u003cstrong\u003eGradle Version Catalog\u003c/strong\u003e resolve tudo isso com um único arquivo TOML centralizado. Neste guia prático, você vai aprender a configurar, migrar e dominar essa feature que já virou padrão em projetos Kotlin modernos.\u003c/p\u003e","title":"Gradle Version Catalog em Kotlin: Guia Prático | Kotlin Brasil"},{"content":"Sobre a vagaA Consensys busca um(a) Engenheiro(a) Mobile Principal para atuar na plataforma do MetaMask em uma posição remota para América do Norte, Europa ou América do Sul.\nResponsabilidadesTrabalhar na plataforma mobile do MetaMask com foco em qualidade, escalabilidade e experiência de desenvolvimento.Atuar com React Native e integrações nativas em Swift e Kotlin.Apoiar práticas de CI/CD, atualizações OTA, bridging e instrumentação de analytics.Colaborar com times distribuídos em decisões técnicas de alto impacto para o produto mobile.RequisitosExperiência sênior ou principal em engenharia mobile.Conhecimento sólido em React Native, Swift e Kotlin.Experiência com pipelines de CI/CD para aplicações mobile.Vivência com integrações entre camadas nativas e código compartilhado.Disponibilidade para trabalho remoto em fusos da América do Norte, Europa ou América do Sul.DiferenciaisExperiência com atualizações OTA em apps mobile.Experiência com analytics em produtos mobile.Vivência em times de plataforma ou infraestrutura para aplicações mobile. ","permalink":"https://kotlin.dev.br/vagas/2rvc8m92vd6ugeb1-consensys-engenheiro-a-mobile-principal-plataforma-metamask/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Consensys busca um(a) Engenheiro(a) Mobile Principal para atuar na plataforma do MetaMask em uma posição remota para América do Norte, Europa ou América do Sul.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eTrabalhar na plataforma mobile do MetaMask com foco em qualidade, escalabilidade e experiência de desenvolvimento.\u003c/li\u003e\u003cli\u003eAtuar com React Native e integrações nativas em Swift e Kotlin.\u003c/li\u003e\u003cli\u003eApoiar práticas de CI/CD, atualizações OTA, bridging e instrumentação de analytics.\u003c/li\u003e\u003cli\u003eColaborar com times distribuídos em decisões técnicas de alto impacto para o produto mobile.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior ou principal em engenharia mobile.\u003c/li\u003e\u003cli\u003eConhecimento sólido em React Native, Swift e Kotlin.\u003c/li\u003e\u003cli\u003eExperiência com pipelines de CI/CD para aplicações mobile.\u003c/li\u003e\u003cli\u003eVivência com integrações entre camadas nativas e código compartilhado.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho remoto em fusos da América do Norte, Europa ou América do Sul.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com atualizações OTA em apps mobile.\u003c/li\u003e\u003cli\u003eExperiência com analytics em produtos mobile.\u003c/li\u003e\u003cli\u003eVivência em times de plataforma ou infraestrutura para aplicações mobile.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) Mobile Principal, Plataforma - MetaMask"},{"content":"Sobre a vagaO Inter\u0026amp;Co busca uma pessoa Analista de Desenvolvimento Mobile II para atuação presencial em Belo Horizonte, Minas Gerais.\nRequisitos e tecnologiasExperiência de nível pleno em desenvolvimento mobile.Conhecimento em Kotlin, Jetpack e arquitetura MVVM.Experiência com Swift e SwiftUI.Prática com testes unitários e testes de interface.Vivência com pipelines de CI/CD, Xcode Cloud e Fastlane. ","permalink":"https://kotlin.dev.br/vagas/4kmupefc13ihkgof-inter-co-analista-de-desenvolvimento-mobile-ii-lifecycle/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO Inter\u0026amp;Co busca uma pessoa Analista de Desenvolvimento Mobile II para atuação presencial em Belo Horizonte, Minas Gerais.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência de nível pleno em desenvolvimento mobile.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e, Jetpack e arquitetura MVVM.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eSwift\u003c/strong\u003e e SwiftUI.\u003c/li\u003e\u003cli\u003ePrática com testes unitários e testes de interface.\u003c/li\u003e\u003cli\u003eVivência com pipelines de CI/CD, Xcode Cloud e Fastlane.\u003c/li\u003e\u003c/ul\u003e","title":"Analista de Desenvolvimento Mobile II - Lifecycle"},{"content":"Sobre a vagaA Descartes busca uma pessoa Desenvolvedora de Software pleno para atuação remota no Brasil, com foco em desenvolvimento backend e serviços distribuídos.\nStack principalLinguagens e frameworks: Java, Kotlin e Spring Framework.Mensageria: Kafka, RabbitMQ e SQS.Arquitetura: microservices e APIs HTTP/REST.Infraestrutura: Docker, Kubernetes, ECS e Fargate.Bancos de dados: SQL, PostgreSQL, Oracle e MongoDB.Práticas e ferramentas: Git e CI/CD.RequisitosExperiência em desenvolvimento de software em nível pleno.Conhecimento em Java, Kotlin e Spring Framework.Experiência com APIs REST, microservices e integração por mensageria.Vivência com bancos relacionais e NoSQL.Familiaridade com containers, orquestração e pipelines de CI/CD. ","permalink":"https://kotlin.dev.br/vagas/503p6xs5bvbr1rlv-descartes-desenvolvedor-de-software-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Descartes busca uma pessoa Desenvolvedora de Software pleno para atuação remota no Brasil, com foco em desenvolvimento backend e serviços distribuídos.\u003c/p\u003e\u003ch3\u003eStack principal\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eLinguagens e frameworks:\u003c/strong\u003e Java, Kotlin e Spring Framework.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eMensageria:\u003c/strong\u003e Kafka, RabbitMQ e SQS.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eArquitetura:\u003c/strong\u003e microservices e APIs HTTP/REST.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eInfraestrutura:\u003c/strong\u003e Docker, Kubernetes, ECS e Fargate.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eBancos de dados:\u003c/strong\u003e SQL, PostgreSQL, Oracle e MongoDB.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003ePráticas e ferramentas:\u003c/strong\u003e Git e CI/CD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento de software em nível pleno.\u003c/li\u003e\u003cli\u003eConhecimento em Java, Kotlin e Spring Framework.\u003c/li\u003e\u003cli\u003eExperiência com APIs REST, microservices e integração por mensageria.\u003c/li\u003e\u003cli\u003eVivência com bancos relacionais e NoSQL.\u003c/li\u003e\u003cli\u003eFamiliaridade com containers, orquestração e pipelines de CI/CD.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor de Software Pleno"},{"content":"Sobre a vagaA WEX busca uma pessoa Engenheira de Software Backend 3, em nível pleno, para atuação remota no Brasil.\nResponsabilidadesDesenvolver e manter serviços backend e APIs.Trabalhar com linguagens como Kotlin, Java, Go e C#.Projetar soluções com bancos de dados SQL e NoSQL.Atuar com conteinerização, Kubernetes, Docker e ambientes em nuvem AWS.Contribuir com testes unitários e de integração.Colaborar com práticas de infraestrutura como código.RequisitosExperiência em desenvolvimento backend.Conhecimento em APIs, bancos SQL e NoSQL.Experiência com Kubernetes, Docker e cloud AWS.Familiaridade com testes unitários e de integração.Capacidade de trabalhar em ambiente remoto e colaborativo.DiferenciaisExperiência com Kotlin em produção.Conhecimento em frameworks front-end.Vivência com infraestrutura como código. ","permalink":"https://kotlin.dev.br/vagas/rl3nkaev9e1yjp1l-wex-engenheiro-a-de-software-backend-3/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA WEX busca uma pessoa Engenheira de Software Backend 3, em nível pleno, para atuação remota no Brasil.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend e APIs.\u003c/li\u003e\u003cli\u003eTrabalhar com linguagens como Kotlin, Java, Go e C#.\u003c/li\u003e\u003cli\u003eProjetar soluções com bancos de dados SQL e NoSQL.\u003c/li\u003e\u003cli\u003eAtuar com conteinerização, Kubernetes, Docker e ambientes em nuvem AWS.\u003c/li\u003e\u003cli\u003eContribuir com testes unitários e de integração.\u003c/li\u003e\u003cli\u003eColaborar com práticas de infraestrutura como código.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento backend.\u003c/li\u003e\u003cli\u003eConhecimento em APIs, bancos SQL e NoSQL.\u003c/li\u003e\u003cli\u003eExperiência com Kubernetes, Docker e cloud AWS.\u003c/li\u003e\u003cli\u003eFamiliaridade com testes unitários e de integração.\u003c/li\u003e\u003cli\u003eCapacidade de trabalhar em ambiente remoto e colaborativo.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin em produção.\u003c/li\u003e\u003cli\u003eConhecimento em frameworks front-end.\u003c/li\u003e\u003cli\u003eVivência com infraestrutura como código.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Backend 3"},{"content":"Sobre a vagaO iFood busca uma Engenheira de Software Android Sênior para atuação presencial em Osasco, São Paulo. Esta é uma vaga afirmativa para mulheres.\nResponsabilidadesDesenvolver e manter aplicações mobile Android com Kotlin.Trabalhar com arquitetura mobile, qualidade de código e integração com APIs REST.Colaborar em iniciativas de CI/CD, testes automatizados, analytics, feature flags e experimentos A/B.Atuar em um contexto mobile que também envolve iOS e Kotlin Multiplatform.RequisitosExperiência sênior em desenvolvimento Android.Conhecimento em Kotlin, Jetpack Compose, MVVM, Clean Architecture e APIs REST.Experiência com testes mobile, como Espresso, Maestro, XCUITest ou ferramentas equivalentes.Vivência com pipelines de CI/CD, Fastlane ou GitLab CI.Conhecimento em monitoramento, crash reporting e ferramentas como Firebase ou Sentry.DiferenciaisExperiência com Kotlin Multiplatform.Conhecimento em Swift, SwiftUI, iOS ou arquitetura VIPER.Experiência com Google Maps, HERE, AI/ML, analytics e feature flags. ","permalink":"https://kotlin.dev.br/vagas/k3qglj6m3oi0kpqq-ifood-engenheira-de-software-android-senior-vaga-afirmativa-par/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma Engenheira de Software Android Sênior para atuação presencial em Osasco, São Paulo. Esta é uma vaga afirmativa para mulheres.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações mobile Android com Kotlin.\u003c/li\u003e\u003cli\u003eTrabalhar com arquitetura mobile, qualidade de código e integração com APIs REST.\u003c/li\u003e\u003cli\u003eColaborar em iniciativas de CI/CD, testes automatizados, analytics, feature flags e experimentos A/B.\u003c/li\u003e\u003cli\u003eAtuar em um contexto mobile que também envolve iOS e Kotlin Multiplatform.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Jetpack Compose, MVVM, Clean Architecture e APIs REST.\u003c/li\u003e\u003cli\u003eExperiência com testes mobile, como Espresso, Maestro, XCUITest ou ferramentas equivalentes.\u003c/li\u003e\u003cli\u003eVivência com pipelines de CI/CD, Fastlane ou GitLab CI.\u003c/li\u003e\u003cli\u003eConhecimento em monitoramento, crash reporting e ferramentas como Firebase ou Sentry.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Kotlin Multiplatform.\u003c/li\u003e\u003cli\u003eConhecimento em Swift, SwiftUI, iOS ou arquitetura VIPER.\u003c/li\u003e\u003cli\u003eExperiência com Google Maps, HERE, AI/ML, analytics e feature flags.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheira de Software Android Sênior (vaga afirmativa para mulheres)"},{"content":"Sobre a vagaA AB InBev busca uma pessoa Desenvolvedora Java Pleno para atuação presencial em Campinas, São Paulo. A vaga envolve desenvolvimento mobile com Kotlin e tecnologias do ecossistema Android.\nRequisitos e tecnologiasExperiência com Java e Kotlin.Conhecimento em desenvolvimento Android.Uso de Retrofit para integração com REST APIs.Experiência com Jetpack Compose, Coroutines e Kotlin Flow.Conhecimento em injeção de dependência com Koin.Testes com JUnit.Experiência com Firebase e Git.Modelo de trabalhoAtuação presencial em Campinas, São Paulo.\n","permalink":"https://kotlin.dev.br/vagas/if6psi8e7kdbgp90-ab-inbev-desenvolvedor-java-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA AB InBev busca uma pessoa Desenvolvedora Java Pleno para atuação presencial em Campinas, São Paulo. A vaga envolve desenvolvimento mobile com Kotlin e tecnologias do ecossistema Android.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Java e Kotlin.\u003c/li\u003e\u003cli\u003eConhecimento em desenvolvimento Android.\u003c/li\u003e\u003cli\u003eUso de Retrofit para integração com REST APIs.\u003c/li\u003e\u003cli\u003eExperiência com Jetpack Compose, Coroutines e Kotlin Flow.\u003c/li\u003e\u003cli\u003eConhecimento em injeção de dependência com Koin.\u003c/li\u003e\u003cli\u003eTestes com JUnit.\u003c/li\u003e\u003cli\u003eExperiência com Firebase e Git.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eAtuação presencial em Campinas, São Paulo.\u003c/p\u003e","title":"Desenvolvedor Java Pleno"},{"content":"Sobre a vagaA AB InBev busca uma pessoa QA Mobile Pleno para atuar presencialmente em Campinas, São Paulo, com foco em qualidade de software para aplicações mobile.\nRequisitos e tecnologiasExperiência em QA para aplicações mobile.Conhecimento em Kotlin.Experiência com Rest Assured e Cucumber.Uso de Jira e Zephyr para gestão e acompanhamento de testes.Formato de trabalhoModelo presencial em Campinas, São Paulo.Nível pleno. ","permalink":"https://kotlin.dev.br/vagas/32rj7gj23ehl6pcf-ab-inbev-qa-mobile-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA AB InBev busca uma pessoa QA Mobile Pleno para atuar presencialmente em Campinas, São Paulo, com foco em qualidade de software para aplicações mobile.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em QA para aplicações mobile.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin.\u003c/li\u003e\u003cli\u003eExperiência com Rest Assured e Cucumber.\u003c/li\u003e\u003cli\u003eUso de Jira e Zephyr para gestão e acompanhamento de testes.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFormato de trabalho\u003c/h3\u003e\u003cul\u003e\u003cli\u003eModelo presencial em Campinas, São Paulo.\u003c/li\u003e\u003cli\u003eNível pleno.\u003c/li\u003e\u003c/ul\u003e","title":"QA Mobile Pleno"},{"content":"Sobre a vagaA AB InBev busca uma pessoa QA Mobile Pleno para atuação presencial em Campinas, São Paulo.\nRequisitos e tecnologiasExperiência com qualidade de software e testes para aplicações mobile.Conhecimento em Kotlin.Experiência com Rest Assured e Cucumber.Uso de Jira e Zephyr para gestão e acompanhamento de testes.Conhecimento de práticas de CI/CD.Modelo de trabalhoVaga presencial em Campinas, São Paulo.\n","permalink":"https://kotlin.dev.br/vagas/vtgxifq8g10b7wh2-ab-inbev-qa-mobile-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA AB InBev busca uma pessoa QA Mobile Pleno para atuação presencial em Campinas, São Paulo.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com qualidade de software e testes para aplicações mobile.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin.\u003c/li\u003e\u003cli\u003eExperiência com Rest Assured e Cucumber.\u003c/li\u003e\u003cli\u003eUso de Jira e Zephyr para gestão e acompanhamento de testes.\u003c/li\u003e\u003cli\u003eConhecimento de práticas de CI/CD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em Campinas, São Paulo.\u003c/p\u003e","title":"QA Mobile Pleno"},{"content":"Sobre a vagaA Parser busca uma pessoa Engenheira Sênior Java/Kotlin para atuar remotamente na Colômbia, com foco em DevOps orientado por IA e automação.\nResponsabilidadesTrabalhar com Java e Kotlin em iniciativas de automação e engenharia de DevOps.Apoiar melhorias em pipelines de CI/CD e práticas de entrega contínua.Usar ferramentas de análise estática para melhorar qualidade, segurança e manutenibilidade do código.Explorar ferramentas de IA, como Claude, para aumentar produtividade e automação no ciclo de desenvolvimento.RequisitosExperiência sênior em engenharia de software.Conhecimento sólido em Java e Kotlin.Experiência com CI/CD e automação de processos de desenvolvimento.Familiaridade com ferramentas de análise estática.Interesse ou experiência prática com ferramentas de IA aplicadas à engenharia de software. ","permalink":"https://kotlin.dev.br/vagas/1tuip1qqypf8fkr1-parser-engenheiro-a-senior-java-kotlin-devops-e-automacao-com-i/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Parser busca uma pessoa Engenheira Sênior Java/Kotlin para atuar remotamente na Colômbia, com foco em DevOps orientado por IA e automação.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eTrabalhar com Java e Kotlin em iniciativas de automação e engenharia de DevOps.\u003c/li\u003e\u003cli\u003eApoiar melhorias em pipelines de CI/CD e práticas de entrega contínua.\u003c/li\u003e\u003cli\u003eUsar ferramentas de análise estática para melhorar qualidade, segurança e manutenibilidade do código.\u003c/li\u003e\u003cli\u003eExplorar ferramentas de IA, como Claude, para aumentar produtividade e automação no ciclo de desenvolvimento.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Java e Kotlin.\u003c/li\u003e\u003cli\u003eExperiência com CI/CD e automação de processos de desenvolvimento.\u003c/li\u003e\u003cli\u003eFamiliaridade com ferramentas de análise estática.\u003c/li\u003e\u003cli\u003eInteresse ou experiência prática com ferramentas de IA aplicadas à engenharia de software.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) Sênior Java/Kotlin (DevOps e Automação com IA)"},{"content":"Sobre a vagaA Plain Concepts busca uma pessoa Engenheira Android com foco em Kotlin para uma posição remota no Brasil.\nResponsabilidadesDesenvolver e manter aplicações Android usando Kotlin.Trabalhar com Jetpack, Coroutines, Flow e integração com REST APIs.Colaborar com o time usando Git no fluxo de desenvolvimento.RequisitosConhecimento em Kotlin e desenvolvimento Android.Familiaridade com Jetpack, Coroutines e Flow.Noções de injeção de dependência com Hilt ou Dagger.Conhecimento em consumo de REST APIs e uso de Git.Não é exigida experiência prévia. ","permalink":"https://kotlin.dev.br/vagas/wvm5lrrd8qw44ecq-plain-concepts-engenheiro-android-desenvolvedor-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Plain Concepts busca uma pessoa Engenheira Android com foco em Kotlin para uma posição remota no Brasil.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações Android usando Kotlin.\u003c/li\u003e\u003cli\u003eTrabalhar com Jetpack, Coroutines, Flow e integração com REST APIs.\u003c/li\u003e\u003cli\u003eColaborar com o time usando Git no fluxo de desenvolvimento.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eConhecimento em Kotlin e desenvolvimento Android.\u003c/li\u003e\u003cli\u003eFamiliaridade com Jetpack, Coroutines e Flow.\u003c/li\u003e\u003cli\u003eNoções de injeção de dependência com Hilt ou Dagger.\u003c/li\u003e\u003cli\u003eConhecimento em consumo de REST APIs e uso de Git.\u003c/li\u003e\u003cli\u003eNão é exigida experiência prévia.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro Android (Desenvolvedor Kotlin)"},{"content":"Sobre a vagaA TRACTIAN busca uma pessoa Engenheira de Software Mobile Sênior para atuação remota, com base em São Paulo, em projetos para iOS e Android.\nStack e foco técnicoKotlin MultiplatformFlutteriOS e AndroidUI/UXDesign responsivoRequisitosExperiência em desenvolvimento Mobile para iOS e Android.Conhecimento em Kotlin Multiplatform e Flutter.Capacidade de criar interfaces responsivas com atenção a UI/UX. ","permalink":"https://kotlin.dev.br/vagas/pnlo6u0sza3zzpub-tractian-engenheiro-a-de-software-mobile-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA TRACTIAN busca uma pessoa Engenheira de Software Mobile Sênior para atuação remota, com base em São Paulo, em projetos para iOS e Android.\u003c/p\u003e\u003ch3\u003eStack e foco técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin Multiplatform\u003c/li\u003e\u003cli\u003eFlutter\u003c/li\u003e\u003cli\u003eiOS e Android\u003c/li\u003e\u003cli\u003eUI/UX\u003c/li\u003e\u003cli\u003eDesign responsivo\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento Mobile para iOS e Android.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin Multiplatform e Flutter.\u003c/li\u003e\u003cli\u003eCapacidade de criar interfaces responsivas com atenção a UI/UX.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Mobile Sênior"},{"content":"Sobre a vagaA Front busca uma pessoa Engenheira de Software Sênior para atuar com arquitetura frontend e React Native em uma posição remota associada a Buenos Aires, Argentina.\nResponsabilidadesTrabalhar na arquitetura de aplicações frontend e mobile.Desenvolver e evoluir soluções com React Native.Atuar em integrações nativas Android usando Kotlin, JNI e Android NDK.Colaborar em uma base de código com TypeScript e componentes nativos.RequisitosExperiência sênior em engenharia de software.Experiência com React Native e arquitetura frontend.Conhecimento de Kotlin no ecossistema Android.Experiência ou familiaridade com TypeScript.Conhecimento de C/C++, JNI ou Android NDK para integração com código nativo. ","permalink":"https://kotlin.dev.br/vagas/n6a1zxi3yeo6hbbt-front-engenheiro-a-de-software-senior-arquitetura-frontend-reac/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Front busca uma pessoa Engenheira de Software Sênior para atuar com arquitetura frontend e React Native em uma posição remota associada a Buenos Aires, Argentina.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eTrabalhar na arquitetura de aplicações frontend e mobile.\u003c/li\u003e\u003cli\u003eDesenvolver e evoluir soluções com React Native.\u003c/li\u003e\u003cli\u003eAtuar em integrações nativas Android usando Kotlin, JNI e Android NDK.\u003c/li\u003e\u003cli\u003eColaborar em uma base de código com TypeScript e componentes nativos.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software.\u003c/li\u003e\u003cli\u003eExperiência com React Native e arquitetura frontend.\u003c/li\u003e\u003cli\u003eConhecimento de Kotlin no ecossistema Android.\u003c/li\u003e\u003cli\u003eExperiência ou familiaridade com TypeScript.\u003c/li\u003e\u003cli\u003eConhecimento de C/C++, JNI ou Android NDK para integração com código nativo.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Sênior - Arquitetura Frontend / React Native"},{"content":"Sobre a vagaVaga remota para Engenheiro(a) de Software Sênior com foco em arquitetura Front-End e React Native, disponível para profissionais em Buenos Aires ou na Argentina.\nRequisitosExperiência sênior em engenharia de software.Experiência com React Native e arquitetura Front-End.Conhecimento em Kotlin, TypeScript, C/C++, JNI e Android NDK.Experiência com desenvolvimento mobile, especialmente no ecossistema Android. ","permalink":"https://kotlin.dev.br/vagas/5nekse1fcio21sck-front-engenheiro-a-de-software-senior-front-end-architecture-re/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga remota para Engenheiro(a) de Software Sênior com foco em arquitetura Front-End e React Native, disponível para profissionais em Buenos Aires ou na Argentina.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software.\u003c/li\u003e\u003cli\u003eExperiência com React Native e arquitetura Front-End.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, TypeScript, C/C++, JNI e Android NDK.\u003c/li\u003e\u003cli\u003eExperiência com desenvolvimento mobile, especialmente no ecossistema Android.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Sênior - Front-End Architecture / React Native"},{"content":"Sobre a vagaA SAP busca uma pessoa Desenvolvedora Java de nível pleno para atuar no SAP Concur Analytics em modelo híbrido em São Leopoldo, Rio Grande do Sul.\nRequisitos e tecnologiasExperiência com desenvolvimento em Java.Conhecimento em Spring Boot.Vivência com Docker, Kubernetes e Helm.Experiência com serviços AWS, incluindo EC2, EKS e DynamoDB.Conhecimento em bancos de dados SQL e NoSQL.Contato com Go, Kotlin e APIs de IA/LLM.Modelo de trabalhoVaga híbrida em São Leopoldo, Rio Grande do Sul, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/133yu94oiukbp8wi-sap-desenvolvedor-java-sap-concur-analytics/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA SAP busca uma pessoa Desenvolvedora Java de nível pleno para atuar no SAP Concur Analytics em modelo híbrido em São Leopoldo, Rio Grande do Sul.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com desenvolvimento em \u003cstrong\u003eJava\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eSpring Boot\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com \u003cstrong\u003eDocker\u003c/strong\u003e, \u003cstrong\u003eKubernetes\u003c/strong\u003e e \u003cstrong\u003eHelm\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com serviços AWS, incluindo \u003cstrong\u003eEC2\u003c/strong\u003e, \u003cstrong\u003eEKS\u003c/strong\u003e e \u003cstrong\u003eDynamoDB\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em bancos de dados \u003cstrong\u003eSQL\u003c/strong\u003e e \u003cstrong\u003eNoSQL\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eContato com \u003cstrong\u003eGo\u003c/strong\u003e, \u003cstrong\u003eKotlin\u003c/strong\u003e e APIs de \u003cstrong\u003eIA/LLM\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga híbrida em São Leopoldo, Rio Grande do Sul, Brasil.\u003c/p\u003e","title":"Desenvolvedor Java - SAP Concur Analytics"},{"content":"Sobre a vagaA Concentrix busca uma pessoa Engenheira de Quality Assurance Sênior, bilíngue, para atuar remotamente em testes de aplicações mobile.\nA posição envolve testes com Detox e ferramentas do ecossistema iOS e Android, trabalhando com tecnologias como Kotlin, Swift e JavaScript.\nResponsabilidadesPlanejar, executar e manter testes para aplicações mobile.Trabalhar com testes automatizados usando Detox.Apoiar testes em Android e iOS com Espresso e XCUITest.Validar integrações com APIs RESTful em XML e JSON.Investigar problemas usando ferramentas como Charles Proxy e Fiddler.Acompanhar atividades e defeitos em Jira.Colaborar com fluxos de build, distribuição e testes usando Bitrise, Fastlane e TestFlight.RequisitosExperiência sênior em Quality Assurance.Experiência prática com Detox para testes mobile.Conhecimento em Kotlin, Swift e JavaScript.Experiência com XCUITest e Espresso.Familiaridade com APIs RESTful, XML e JSON.Experiência com ferramentas de proxy e depuração como Charles Proxy ou Fiddler.Perfil bilíngue.Local de trabalhoVaga remota para profissionais no México, Costa Rica ou Argentina.\n","permalink":"https://kotlin.dev.br/vagas/m1r8wp8jjmc7fsql-concentrix-engenheiro-a-de-qa-senior-com-detox-bilingue/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Concentrix busca uma pessoa Engenheira de Quality Assurance Sênior, bilíngue, para atuar remotamente em testes de aplicações mobile.\u003c/p\u003e\u003cp\u003eA posição envolve testes com Detox e ferramentas do ecossistema iOS e Android, trabalhando com tecnologias como Kotlin, Swift e JavaScript.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003ePlanejar, executar e manter testes para aplicações mobile.\u003c/li\u003e\u003cli\u003eTrabalhar com testes automatizados usando Detox.\u003c/li\u003e\u003cli\u003eApoiar testes em Android e iOS com Espresso e XCUITest.\u003c/li\u003e\u003cli\u003eValidar integrações com APIs RESTful em XML e JSON.\u003c/li\u003e\u003cli\u003eInvestigar problemas usando ferramentas como Charles Proxy e Fiddler.\u003c/li\u003e\u003cli\u003eAcompanhar atividades e defeitos em Jira.\u003c/li\u003e\u003cli\u003eColaborar com fluxos de build, distribuição e testes usando Bitrise, Fastlane e TestFlight.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em Quality Assurance.\u003c/li\u003e\u003cli\u003eExperiência prática com Detox para testes mobile.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Swift e JavaScript.\u003c/li\u003e\u003cli\u003eExperiência com XCUITest e Espresso.\u003c/li\u003e\u003cli\u003eFamiliaridade com APIs RESTful, XML e JSON.\u003c/li\u003e\u003cli\u003eExperiência com ferramentas de proxy e depuração como Charles Proxy ou Fiddler.\u003c/li\u003e\u003cli\u003ePerfil bilíngue.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga remota para profissionais no México, Costa Rica ou Argentina.\u003c/p\u003e","title":"Engenheiro(a) de QA Sênior com Detox (Bilíngue)"},{"content":"Sobre a vagaInter\u0026amp;Co busca uma pessoa Desenvolvedora Mobile iOS Sênior para atuação presencial em Belo Horizonte, Curitiba ou Recife.\nRequisitosExperiência sênior em desenvolvimento mobile iOS.Conhecimento em SwiftUI.Experiência com integração via REST API.Experiência com testes automatizados.Conhecimento em Java e Kotlin.Modelo de trabalhoAtuação presencial em Belo Horizonte, Curitiba ou Recife.\n","permalink":"https://kotlin.dev.br/vagas/4myb34szcduux75c-inter-co-desenvolvedor-mobile-ios-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eInter\u0026amp;Co busca uma pessoa Desenvolvedora Mobile iOS Sênior para atuação presencial em Belo Horizonte, Curitiba ou Recife.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento mobile iOS.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eSwiftUI\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com integração via \u003cstrong\u003eREST API\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003etestes automatizados\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eJava\u003c/strong\u003e e \u003cstrong\u003eKotlin\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eAtuação presencial em Belo Horizonte, Curitiba ou Recife.\u003c/p\u003e","title":"Desenvolvedor Mobile iOS Sênior"},{"content":"Durante muito tempo, a conversa sobre arquitetura backend parecia presa entre dois extremos: o monólito bagunçado e os microsserviços complexos demais. Em 2026, uma abordagem voltou com força para o centro do debate técnico: o monólito modular. E quando combinamos isso com Kotlin + Spring, o resultado pode ser uma base de código mais organizada, testável e simples de operar.\nEsse tema ganhou relevância recente com discussões no ecossistema JetBrains e Spring, especialmente em conteúdos sobre Spring Modulith e modelagem por domínio. Para equipes que usam Kotlin no backend, o assunto é valioso porque oferece um caminho intermediário muito prático: manter um único deploy, mas com fronteiras internas claras.\nSe você já acompanha nossos conteúdos sobre Kotlin server-side em 2026, Kotlin com Spring Boot e o guia de backend com Spring, este artigo aprofunda o próximo passo arquitetural.\nO que é um monólito modular? Um monólito modular é uma aplicação implantada como uma única unidade, mas organizada em módulos que representam domínios ou capacidades de negócio. Em vez de colocar tudo em uma estrutura genérica de controller, service e repository soltos pelo projeto inteiro, você separa responsabilidades por contexto.\nEm um sistema de e-commerce, por exemplo, seria natural ter módulos como:\nproduto pedido pagamento estoque cliente Cada módulo tem sua própria lógica, contratos internos, eventos e acesso a dados. O deploy continua simples, mas o acoplamento tende a cair muito.\nPor que esse tema voltou a crescer em 2026? Existem três razões principais.\n1. Cansaço com complexidade operacional Muitas equipes perceberam que adotar microsserviços cedo demais gera overhead de deploy, observabilidade, segurança, tracing distribuído e governança.\n2. Busca por domínio mais explícito Times maduros querem refletir melhor o negócio na estrutura do código. Monólitos modulares ajudam nisso.\n3. Ferramentas melhores Com o Spring Modulith, ficou mais fácil declarar limites entre módulos, testar arquitetura e detectar violações de dependência.\nOu seja: a ideia não é “voltar ao passado”, mas sim construir sistemas mais sustentáveis com ferramentas atuais.\nEstrutura de módulos em Kotlin Vamos imaginar uma aplicação simples de pedidos. Em vez de começar pela clássica divisão horizontal, podemos estruturar o projeto assim:\nsrc/main/kotlin/br/dev/kotlinbrasil/app ├── pedido │ ├── PedidoController.kt │ ├── PedidoService.kt │ ├── PedidoRepository.kt │ └── package-info.java ├── produto │ ├── ProdutoController.kt │ ├── ProdutoService.kt │ ├── ProdutoRepository.kt │ └── package-info.java ├── pagamento │ ├── PagamentoService.kt │ ├── PagamentoGateway.kt │ └── package-info.java └── Application.kt Essa organização conversa bem com Kotlin porque a linguagem favorece código mais coeso, conciso e expressivo. Se você está revisando fundamentos importantes, vale retomar nosso guia completo de Kotlin e também o conteúdo sobre design patterns em Kotlin.\nConfigurando Spring Modulith com Kotlin Um setup simplificado pode começar assim:\nplugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.3.20\u0026#34; kotlin(\u0026#34;plugin.spring\u0026#34;) version \u0026#34;2.3.20\u0026#34; id(\u0026#34;org.springframework.boot\u0026#34;) version \u0026#34;3.4.4\u0026#34; id(\u0026#34;io.spring.dependency-management\u0026#34;) version \u0026#34;1.1.7\u0026#34; } repositories { mavenCentral() } dependencies { implementation(\u0026#34;org.springframework.boot:spring-boot-starter-web\u0026#34;) implementation(\u0026#34;org.springframework.boot:spring-boot-starter-data-jpa\u0026#34;) implementation(\u0026#34;org.springframework.modulith:spring-modulith-starter-core\u0026#34;) testImplementation(\u0026#34;org.springframework.modulith:spring-modulith-starter-test\u0026#34;) } A ideia é usar o Spring Boot normalmente, mas adicionar a camada do Modulith para declarar e validar fronteiras entre módulos.\nDeclarando o aplicativo como modulith Na classe principal, a aplicação pode ficar assim:\nimport org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication import org.springframework.modulith.Modulithic @Modulithic @SpringBootApplication class KotlinBrasilApplication fun main(args: Array\u0026lt;String\u0026gt;) { runApplication\u0026lt;KotlinBrasilApplication\u0026gt;(*args) } Essa anotação indica que a aplicação deve ser tratada como um conjunto de módulos bem definidos, com suporte a documentação e verificação arquitetural.\nDeclarando dependências permitidas entre módulos Um dos recursos mais úteis do Spring Modulith é permitir declarar explicitamente quais módulos podem depender de quais outros.\nNo package-info.java do módulo pedido, por exemplo:\n@org.springframework.modulith.ApplicationModule( allowedDependencies = {\u0026#34;produto\u0026#34;, \u0026#34;pagamento\u0026#34;} ) package br.dev.kotlinbrasil.app.pedido; Com isso, o módulo pedido pode conversar com produto e pagamento, mas não deveria acessar diretamente cliente, por exemplo, se isso não fizer sentido arquitetural.\nEsse tipo de restrição ajuda muito a evitar o crescimento silencioso de acoplamento. Em projetos Kotlin que duram anos, esse cuidado faz diferença real.\nExemplo prático: módulo de produto Vamos definir um módulo de produto com uma API mínima.\npackage br.dev.kotlinbrasil.app.produto data class Produto( val id: Long, val nome: String, val preco: Double, val estoqueDisponivel: Int, ) interface ProdutoRepository { fun buscarPorId(id: Long): Produto? } class ProdutoService( private val produtoRepository: ProdutoRepository, ) { fun validarDisponibilidade(produtoId: Long, quantidade: Int): Boolean { val produto = produtoRepository.buscarPorId(produtoId) ?: throw IllegalArgumentException(\u0026#34;Produto não encontrado\u0026#34;) return produto.estoqueDisponivel \u0026gt;= quantidade } } Perceba que o objetivo não é apenas ter classes separadas, mas encapsular a lógica de um domínio específico.\nExemplo prático: módulo de pedido Agora, o módulo de pedido pode depender de produto sem conhecer detalhes internos desnecessários.\npackage br.dev.kotlinbrasil.app.pedido import br.dev.kotlinbrasil.app.produto.ProdutoService data class CriarPedidoCommand( val produtoId: Long, val quantidade: Int, val clienteId: String, ) data class Pedido( val id: Long, val produtoId: Long, val quantidade: Int, val clienteId: String, val status: String, ) class PedidoService( private val produtoService: ProdutoService, private val pedidoRepository: PedidoRepository, ) { fun criar(command: CriarPedidoCommand): Pedido { require(produtoService.validarDisponibilidade(command.produtoId, command.quantidade)) { \u0026#34;Produto sem estoque disponível\u0026#34; } val pedido = Pedido( id = System.currentTimeMillis(), produtoId = command.produtoId, quantidade = command.quantidade, clienteId = command.clienteId, status = \u0026#34;CRIADO\u0026#34;, ) return pedidoRepository.salvar(pedido) } } interface PedidoRepository { fun salvar(pedido: Pedido): Pedido } Essa interação parece simples, mas já mostra uma vantagem importante: o fluxo respeita domínio e responsabilidade.\nQuando usar eventos em vez de chamada direta? Nem toda integração entre módulos precisa ser síncrona. Em muitos casos, eventos de aplicação deixam o sistema mais desacoplado.\nPor exemplo: depois de criar um pedido, pode ser interessante disparar um evento para o módulo de pagamento iniciar o processamento.\npackage br.dev.kotlinbrasil.app.pedido import org.springframework.context.ApplicationEventPublisher class PedidoService( private val produtoService: ProdutoService, private val pedidoRepository: PedidoRepository, private val eventPublisher: ApplicationEventPublisher, ) { fun criar(command: CriarPedidoCommand): Pedido { require(produtoService.validarDisponibilidade(command.produtoId, command.quantidade)) { \u0026#34;Produto sem estoque disponível\u0026#34; } val pedido = pedidoRepository.salvar( Pedido( id = System.currentTimeMillis(), produtoId = command.produtoId, quantidade = command.quantidade, clienteId = command.clienteId, status = \u0026#34;CRIADO\u0026#34;, ) ) eventPublisher.publishEvent(PedidoCriadoEvent(pedido.id, pedido.clienteId)) return pedido } } data class PedidoCriadoEvent( val pedidoId: Long, val clienteId: String, ) No módulo de pagamento:\npackage br.dev.kotlinbrasil.app.pagamento import br.dev.kotlinbrasil.app.pedido.PedidoCriadoEvent import org.springframework.modulith.events.ApplicationModuleListener class PagamentoListener { @ApplicationModuleListener fun aoCriarPedido(event: PedidoCriadoEvent) { println(\u0026#34;Iniciando pagamento do pedido ${event.pedidoId} para cliente ${event.clienteId}\u0026#34;) } } Esse padrão é especialmente útil quando você quer diminuir acoplamento temporal entre módulos.\nComo o Spring Modulith ajuda nos testes? Aqui entra uma das partes mais valiosas da abordagem. Não basta organizar módulos visualmente; é preciso validar se a arquitetura está sendo respeitada.\nUm teste simples pode verificar a estrutura do modulith:\nimport org.junit.jupiter.api.Test import org.springframework.modulith.core.ApplicationModules class ArquiteturaModularTest { @Test fun `deve validar a estrutura modular da aplicacao`() { ApplicationModules.of(KotlinBrasilApplication::class.java) .verify() } } Esse tipo de teste ajuda a detectar violações logo cedo. Se um módulo começar a acessar outro sem permissão, a suíte acusa.\nTambém é possível testar módulos de forma mais isolada, o que melhora muito a confiança do time ao evoluir o sistema.\nSe seu foco é qualidade de backend, vale revisar nosso guia de testes em Kotlin e o conteúdo sobre JUnit 5 e MockK.\nMonólito modular não é apenas organização de pastas Esse é um erro comum. Muita gente acha que basta agrupar arquivos por pacote e pronto. Não é assim.\nUm monólito modular de verdade exige:\nfronteiras explícitas; dependências controladas; contratos claros entre módulos; testes arquiteturais; eventos ou APIs internas bem definidas; disciplina para evitar atalhos. Sem isso, você acaba apenas com um monólito com pastas mais bonitas.\nQuais são as principais vantagens? Simplicidade operacional Você continua com um único deploy, um pipeline principal e menos overhead de infraestrutura.\nMelhor modelagem de domínio Os módulos refletem áreas do negócio, o que ajuda tanto a engenharia quanto a comunicação com produto.\nTestabilidade Com limites melhores, fica mais fácil testar partes específicas da aplicação.\nEvolução gradual Se um dia fizer sentido extrair um módulo para microsserviço, o caminho tende a ser menos traumático.\nE as limitações? É importante não romantizar.\nMonólito modular ainda é monólito. Isso significa que:\no deploy continua único; a escalabilidade mais fina por serviço não existe da mesma forma; falhas graves ainda podem impactar a aplicação toda; disciplina arquitetural continua sendo obrigatória. Ou seja: essa abordagem não substitui todos os casos de microsserviços. Mas para muitas equipes, ela resolve melhor o problema real.\nObservabilidade também importa aqui Uma parte interessante do conteúdo recente sobre monólitos modulares é a ligação com observabilidade. Mesmo com deploy único, vale monitorar interações entre módulos, eventos internos e fluxos críticos.\nVocê pode combinar essa abordagem com práticas já conhecidas no ecossistema Kotlin, como:\nlogs estruturados; métricas por domínio; tracing com OpenTelemetry; documentação de interação entre módulos. Nesse ponto, nosso artigo sobre observabilidade em Kotlin complementa bem a discussão.\nQuando faz sentido adotar monólito modular em Kotlin? Essa abordagem costuma ser excelente para:\nprodutos em crescimento que ainda não precisam de microsserviços; times pequenos ou médios; plataformas internas; SaaS B2B em fase de consolidação; sistemas que precisam de mais organização sem explosão operacional. Ela também pode ser uma ótima etapa intermediária para projetos legados que hoje sofrem com acoplamento excessivo.\nConclusão O monólito modular em Kotlin com Spring é uma das pautas mais úteis de 2026 para times backend porque responde a um problema muito concreto: como crescer sem afundar em complexidade cedo demais. Com Spring Modulith, fica mais fácil declarar módulos, verificar dependências, testar arquitetura e criar uma base mais sustentável para evoluir o produto.\nPara equipes que já usam Kotlin com Spring Boot, estudam arquitetura limpa ou querem fortalecer a estrutura do backend sem partir direto para microsserviços, essa é uma abordagem que vale muito acompanhar.\nSe quiser continuar estudando, veja também:\nGuia de Kotlin para backend Kotlin server-side em 2026 Kotlin e microsserviços Ktor vs Spring Boot Para quem trabalha com backend poliglota, vale observar como Go aborda modularização com packages e internal — uma filosofia diferente, mas com o mesmo objetivo de manter fronteiras claras entre componentes.\nO mais importante é lembrar: arquitetura boa não é a mais complexa, e sim a que permite evoluir com clareza, segurança e ritmo sustentável.\n","permalink":"https://kotlin.dev.br/blog/monolito-modular-kotlin-spring-2026/","summary":"\u003cp\u003eDurante muito tempo, a conversa sobre arquitetura backend parecia presa entre dois extremos: o monólito bagunçado e os microsserviços complexos demais. Em 2026, uma abordagem voltou com força para o centro do debate técnico: o \u003cstrong\u003emonólito modular\u003c/strong\u003e. E quando combinamos isso com \u003cstrong\u003eKotlin + Spring\u003c/strong\u003e, o resultado pode ser uma base de código mais organizada, testável e simples de operar.\u003c/p\u003e\n\u003cp\u003eEsse tema ganhou relevância recente com discussões no ecossistema JetBrains e Spring, especialmente em conteúdos sobre \u003cstrong\u003eSpring Modulith\u003c/strong\u003e e modelagem por domínio. Para equipes que usam Kotlin no backend, o assunto é valioso porque oferece um caminho intermediário muito prático: manter um único deploy, mas com fronteiras internas claras.\u003c/p\u003e","title":"Monólito Modular em Kotlin: Spring em 2026 | Kotlin Brasil"},{"content":"A adoção de IA em produtos Kotlin está acelerando em 2026. Só que existe um problema que muita equipe descobre tarde demais: não basta integrar um modelo de linguagem e esperar que tudo funcione bem em produção. Quando surgem respostas inconsistentes, aumento de custo, latência inesperada ou falhas em tools, você precisa enxergar o que aconteceu dentro do fluxo do agente. É exatamente nesse cenário que entra o Tracy, a biblioteca de observabilidade para aplicações de IA em Kotlin apresentada pela JetBrains.\nSe você já acompanhou nosso conteúdo sobre Koog, o framework Kotlin para agentes de IA, faz sentido dar o próximo passo: entender como monitorar esses agentes com mais profundidade. E se quiser uma visão mais ampla do cenário, vale ler também nosso artigo sobre Kotlin e IA/Machine Learning.\nO que é o Tracy? O Tracy é uma biblioteca Kotlin pensada para adicionar observabilidade de IA a aplicações que usam LLMs, tools e fluxos de execução mais complexos. Em vez de rastrear só logs genéricos, ele permite acompanhar spans, chamadas de modelo, execuções de ferramentas, tempos de resposta e a relação entre cada etapa da aplicação.\nNa prática, isso ajuda a responder perguntas como:\nqual parte do fluxo do agente está mais lenta; qual tool falhou e em que contexto; qual prompt gerou determinada saída; quanto tempo cada chamada ao modelo levou; quais etapas do pipeline estão elevando custo e latência. Para times que estão construindo apps com LLMs em Kotlin, isso aproxima o ecossistema do nível de maturidade que já esperamos em APIs e microsserviços tradicionais. Se você trabalha com backend, essa lógica conversa muito bem com temas que já abordamos em observabilidade para aplicações Kotlin, Kotlin server-side e Kotlin DevOps e CI/CD.\nPor que o Tracy virou tema importante em 2026? O momento é oportuno por alguns motivos.\nPrimeiro, o Kotlin está ganhando mais espaço em produtos com IA. Isso aparece em anúncios recentes da JetBrains, em frameworks novos e em talks de conferência focadas em produtividade, agentes e integrações inteligentes.\nSegundo, o ecossistema saiu da fase de simples protótipos. Em 2026, muita equipe já quer colocar recursos de IA em produção. E quando isso acontece, não dá mais para depender apenas de println, logs soltos ou dashboards genéricos.\nTerceiro, o Tracy se conecta com uma tendência forte do mercado: observabilidade específica para LLMs, incluindo tracing de prompts, tools e fluxos híbridos. Em outras palavras, ele tenta resolver um problema real de engenharia, não apenas um hype passageiro.\nQuais recursos o Tracy oferece? De acordo com o anúncio da JetBrains, o Tracy traz um conjunto de recursos muito relevante para times Kotlin:\ncriação de spans com withSpan; instrumentação de clientes LLM; tracing de tools e funções com @Trace; integração com OpenTelemetry; exportação para backends compatíveis, como Langfuse e W\u0026amp;B Weave; possibilidade de rastrear conteúdo sensível apenas quando necessário. Isso é importante porque muitas equipes já usam padrões observáveis em aplicações distribuídas. O Tracy reaproveita essa mentalidade e leva a mesma disciplina para apps com IA.\nExemplo 1: criando spans com withSpan Uma das formas mais simples de começar é envolver blocos de execução com spans nomeados. Isso facilita medir tempo e enxergar a árvore de execução.\nimport ai.tracy.Tracy import ai.tracy.withSpan import kotlinx.coroutines.runBlocking class ResumoService( private val clienteLLM: ClienteLLM, ) { suspend fun gerarResumo(texto: String): String = withSpan(\u0026#34;gerar-resumo-artigo\u0026#34;) { clienteLLM.gerar( prompt = \u0026#34;Resuma o texto a seguir em 5 bullets em português: $texto\u0026#34; ) } } fun main() = runBlocking { val service = ResumoService(clienteLLM = ClienteLLMFake()) val resumo = withSpan(\u0026#34;fluxo-homepage\u0026#34;) { service.gerarResumo(\u0026#34;Kotlin continua crescendo no ecossistema Android e backend...\u0026#34;) } println(resumo) } O ponto não é apenas medir tempo. O ganho real está em visualizar a relação entre o span pai e os spans filhos, entendendo se o gargalo está no prompt, na chamada ao modelo ou em outra etapa do fluxo.\nExemplo 2: instrumentando um cliente LLM Outro caso comum é registrar automaticamente chamadas a um provedor de modelo. O Tracy foi apresentado com suporte a integrações em stacks como OkHttp, Ktor e clientes de provedores de IA.\nimport ai.tracy.instrument import io.ktor.client.HttpClient fun criarClienteInstrumentado(): HttpClient { val client = HttpClient() return instrument(client) } Em um projeto real, isso pode ser combinado com um serviço que chama um modelo para classificar tickets, gerar conteúdo, responder perguntas internas ou enriquecer buscas semânticas.\nSe o seu backend já usa Ktor para criar APIs com Kotlin ou o guia de backend com Ktor, esse tipo de instrumentação ajuda a trazer mais previsibilidade para endpoints com IA.\nExemplo 3: rastreando tools com @Trace Em apps de agentes, grande parte dos problemas aparece nas ferramentas chamadas pelo modelo. Uma tool pode buscar dados no banco, consultar uma API externa, validar contexto do usuário ou disparar um processo interno. Se isso falha sem rastreamento adequado, fica difícil depurar.\nimport ai.tracy.Trace class CarteiraService { @Trace suspend fun buscarSaldo(usuarioId: String): String { // Simulação de consulta externa return \u0026#34;Saldo disponível de R$ 12.450,00 para o usuário $usuarioId\u0026#34; } @Trace suspend fun listarUltimasTransacoes(usuarioId: String): List\u0026lt;String\u0026gt; { return listOf( \u0026#34;Pix recebido: R$ 850,00\u0026#34;, \u0026#34;Assinatura SaaS: R$ 59,90\u0026#34;, \u0026#34;Transferência enviada: R$ 300,00\u0026#34;, ) } } Esse padrão fica ainda mais útil quando o agente precisa decidir qual tool chamar, em que ordem e com quais parâmetros. Se você se interessa por esse desenho arquitetural, vale revisar nosso conteúdo sobre Kotlin Flow e coroutines em Kotlin, porque esses conceitos costumam aparecer juntos em fluxos de IA orientados a eventos e operações assíncronas.\nExemplo 4: combinando Tracy com um agente Kotlin Vamos imaginar um agente simples que responde dúvidas sobre carreira em Kotlin usando tools internas e um modelo externo.\nimport ai.tracy.withSpan import kotlinx.coroutines.runBlocking class AgenteCarreiraKotlin( private val llm: ClienteLLM, private val carteiraService: CarteiraService, ) { suspend fun responder(pergunta: String, usuarioId: String): String = withSpan(\u0026#34;agente-carreira-kotlin\u0026#34;) { val saldo = carteiraService.buscarSaldo(usuarioId) val transacoes = carteiraService.listarUltimasTransacoes(usuarioId) llm.gerar( prompt = \u0026#34;\u0026#34;\u0026#34; Responda em português brasileiro. Pergunta do usuário: $pergunta Contexto financeiro: $saldo Últimas transações: ${transacoes.joinToString()} \u0026#34;\u0026#34;\u0026#34;.trimIndent() ) } } fun main() = runBlocking { val agente = AgenteCarreiraKotlin( llm = ClienteLLMFake(), carteiraService = CarteiraService(), ) println(agente.responder(\u0026#34;Como organizar meus estudos para migrar de Java para Kotlin?\u0026#34;, \u0026#34;user-42\u0026#34;)) } Com tracing adequado, você consegue saber se a latência veio da tool de saldo, do histórico de transações, da geração do LLM ou de uma combinação de fatores.\nTracy e OpenTelemetry: por que isso pesa tanto? Um dos pontos mais fortes do Tracy é a integração com OpenTelemetry, padrão já consolidado em observabilidade moderna. Isso reduz o atrito para equipes que já usam ferramentas como Jaeger, Zipkin, Grafana ou plataformas compatíveis.\nNa prática, significa que você não precisa reinventar o pipeline inteiro de telemetria só porque começou a usar IA. Em vez disso, você amplia o que já faz sentido no stack atual.\nEsse alinhamento é valioso principalmente em cenários de:\nAPIs backend com recursos de IA; plataformas internas com assistentes de suporte; pipelines de classificação, resumo e extração; agentes que combinam LLM, banco de dados e sistemas internos. Se você já trabalha com Kotlin em microsserviços ou com Kotlin e Kubernetes, esse tipo de integração tende a ser especialmente interessante.\nQuando Tracy faz mais sentido? Nem todo projeto precisa desse nível de rastreamento desde o primeiro dia. Mas o Tracy faz muito sentido quando você tem:\n1. Fluxos com múltiplas tools Se o modelo pode disparar ações diferentes, o tracing ajuda a entender sequência, custo e erro.\n2. Uso real em produção Quando usuários de verdade dependem do recurso, você precisa debugar comportamento com mais segurança.\n3. Metas de latência e custo Sem observabilidade, fica difícil saber se o tempo de resposta aumentou por causa do modelo, da rede ou de uma tool específica.\n4. Times que já usam observabilidade no backend Nesses casos, Tracy se encaixa como uma evolução natural da disciplina de engenharia.\nBoas práticas ao usar Tracy em apps Kotlin com IA Se você decidir experimentar a biblioteca, algumas práticas podem ajudar:\nnomeie spans de forma clara e consistente; separe spans de lógica de negócio e spans de chamada ao modelo; evite registrar dados sensíveis sem necessidade; acompanhe custo e latência por tipo de operação; combine tracing com logs estruturados e métricas; use ambientes de teste antes de ligar tudo em produção. Também vale lembrar que observabilidade não substitui arquitetura bem desenhada. Se o fluxo do agente já nasce confuso, o tracing vai mostrar o problema, mas não resolver sozinho. Para isso, conteúdos como Kotlin design patterns e Clean Architecture com Kotlin podem ajudar bastante.\nTracy compete com Koog? Não exatamente. As duas ferramentas se complementam.\nO Koog resolve a orquestração de agentes e a construção de fluxos com LLMs e tools. O Tracy resolve o problema de enxergar esses fluxos com mais clareza em runtime. Em muitos projetos, faz sentido usar ambos: um para construir, outro para observar.\nEssa combinação é especialmente interessante para equipes que querem sair do estágio de experimento e tratar IA como parte séria do produto.\nVale a pena acompanhar o Tracy agora? Sim, principalmente se você desenvolve com Kotlin e quer explorar IA sem abrir mão de práticas maduras de engenharia. O Tracy é relevante porque ataca uma dor real: a falta de visibilidade operacional em aplicações com LLMs.\nAlém disso, ele surge em um momento em que o ecossistema Kotlin está abrindo novas frentes em IA, tooling e produtividade. Isso dá ao tema potencial forte de adoção nos próximos meses, especialmente entre times backend e plataformas internas.\nConclusão O Tracy é uma das novidades mais interessantes do ecossistema Kotlin em 2026 porque conecta dois mundos que precisam andar juntos: IA aplicada e observabilidade de produção. Em vez de tratar agentes e fluxos com LLM como caixas-pretas, a proposta da biblioteca é tornar cada etapa mais rastreável, auditável e otimizada.\nSe você já está estudando agentes com Koog, construindo APIs com Ktor ou ampliando a estratégia de observabilidade em Kotlin, o Tracy entra como uma peça natural do stack.\nPara continuar explorando o ecossistema, recomendamos também:\nKotlin 2.4.0 Beta1: novidades em 2026 Exposed 1.0 com R2DBC em Kotlin Tendências Kotlin 2026 Glossário Kotlin No ecossistema de observabilidade, Go é a linguagem por trás de ferramentas como Prometheus e Grafana, e Python domina o tracing de aplicações de IA com LangSmith e Weights \u0026amp; Biases. O Tracy preenche essa lacuna no ecossistema Kotlin, trazendo observabilidade de IA nativa para a JVM.\nSe quiser, o próximo passo é testar Tracy em um serviço pequeno, instrumentar um fluxo crítico e comparar o antes e depois na sua visibilidade operacional.\n","permalink":"https://kotlin.dev.br/blog/tracy-observabilidade-ia-kotlin-2026/","summary":"\u003cp\u003eA adoção de IA em produtos Kotlin está acelerando em 2026. Só que existe um problema que muita equipe descobre tarde demais: não basta integrar um modelo de linguagem e esperar que tudo funcione bem em produção. Quando surgem respostas inconsistentes, aumento de custo, latência inesperada ou falhas em tools, você precisa enxergar o que aconteceu dentro do fluxo do agente. É exatamente nesse cenário que entra o \u003cstrong\u003eTracy\u003c/strong\u003e, a biblioteca de observabilidade para aplicações de IA em Kotlin apresentada pela JetBrains.\u003c/p\u003e","title":"Tracy para Kotlin: Observabilidade de IA em 2026 | Kotlin Brasil"},{"content":"Depois de anos em desenvolvimento, o Exposed 1.0 finalmente chegou — e é uma release que muda o jogo para quem trabalha com banco de dados em Kotlin. O framework SQL da JetBrains agora oferece suporte oficial a R2DBC, uma API estável com garantia de compatibilidade, e melhorias significativas de performance.\nSe você já conhece o Exposed pelo nosso tutorial completo do framework, prepare-se: a versão 1.0 traz tudo que a comunidade vinha pedindo. Vamos ver o que mudou na prática.\nO que há de novo no Exposed 1.0? 1. Suporte a R2DBC (Reactive Relational Database Connectivity) Essa era a feature mais pedida pela comunidade. Até a versão 0.x, o Exposed trabalhava exclusivamente com JDBC, o que significava acesso bloqueante ao banco. Agora, com o módulo exposed-r2dbc, você pode usar drivers reativos para acesso não-bloqueante.\nOs bancos suportados via R2DBC são:\nBanco Driver R2DBC PostgreSQL r2dbc-postgresql MySQL r2dbc-mysql MariaDB r2dbc-mariadb H2 r2dbc-h2 Oracle r2dbc-oracle SQL Server r2dbc-mssql 2. API estável Com a versão 1.0, a JetBrains garante que não haverá breaking changes até a próxima major release. Isso significa que você pode adotar o Exposed em produção com confiança de que atualizações menores não vão quebrar seu código.\n3. Melhorias de performance A 1.0 traz otimizações internas no processamento de queries e no gerenciamento de conexões, resultando em menor overhead por transação.\nSetup com R2DBC Primeiro, adicione as dependências no build.gradle.kts:\n// build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.3.20\u0026#34; } repositories { mavenCentral() } dependencies { // Módulo R2DBC do Exposed implementation(\u0026#34;org.jetbrains.exposed:exposed-r2dbc:1.0.0\u0026#34;) // Driver R2DBC para PostgreSQL implementation(\u0026#34;org.postgresql:r2dbc-postgresql:1.0.7.RELEASE\u0026#34;) // Coroutines (necessário para R2DBC) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.10.1\u0026#34;) } Se quiser manter o acesso JDBC tradicional junto com R2DBC, basta adicionar ambos os módulos — eles coexistem sem conflito. Para uma aplicação web completa, use o tutorial de Ktor com Exposed como base e depois substitua a camada JDBC por R2DBC quando fizer sentido.\nConectando com R2DBC A conexão R2DBC usa a classe R2dbcDatabase:\nimport org.jetbrains.exposed.sql.r2dbc.R2dbcDatabase import org.jetbrains.exposed.sql.r2dbc.R2dbcDatabaseConfig import io.r2dbc.spi.ConnectionFactoryOptions import io.r2dbc.spi.IsolationLevel val database = R2dbcDatabase.connect( url = \u0026#34;r2dbc:postgresql://localhost:5432/kotlinbrasil\u0026#34;, databaseConfig = R2dbcDatabaseConfig { defaultMaxAttempts = 3 defaultR2dbcIsolationLevel = IsolationLevel.READ_COMMITTED connectionFactoryOptions { option(ConnectionFactoryOptions.USER, \u0026#34;dev_kotlin\u0026#34;) option(ConnectionFactoryOptions.PASSWORD, \u0026#34;senha_segura\u0026#34;) } } ) Note que a URL segue o padrão r2dbc:driver://host:porta/banco, diferente do jdbc: tradicional.\nDefinindo tabelas (mesmo esquema de antes) A boa notícia é que a definição de tabelas não muda. Se você já tem tabelas definidas com Exposed DSL, elas funcionam tanto com JDBC quanto com R2DBC:\nimport org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.javatime.datetime import java.time.LocalDateTime object Desenvolvedores : Table(\u0026#34;desenvolvedores\u0026#34;) { val id = integer(\u0026#34;id\u0026#34;).autoIncrement() val nome = varchar(\u0026#34;nome\u0026#34;, 100) val linguagem = varchar(\u0026#34;linguagem\u0026#34;, 50).default(\u0026#34;Kotlin\u0026#34;) val senioridade = varchar(\u0026#34;senioridade\u0026#34;, 20) val salario = decimal(\u0026#34;salario\u0026#34;, 10, 2) val criadoEm = datetime(\u0026#34;criado_em\u0026#34;).defaultExpression(CurrentDateTime) override val primaryKey = PrimaryKey(id) } object Projetos : Table(\u0026#34;projetos\u0026#34;) { val id = integer(\u0026#34;id\u0026#34;).autoIncrement() val nome = varchar(\u0026#34;nome\u0026#34;, 200) val descricao = text(\u0026#34;descricao\u0026#34;) val desenvolvedorId = integer(\u0026#34;desenvolvedor_id\u0026#34;).references(Desenvolvedores.id) val ativo = bool(\u0026#34;ativo\u0026#34;).default(true) override val primaryKey = PrimaryKey(id) } Se termos como Table, varchar ou autoIncrement parecem novos, confira nosso glossário de termos Kotlin e o tutorial de classes e objetos.\nCRUD reativo com R2DBC Agora vem a parte interessante: todas as operações com R2DBC são suspend functions, integrando perfeitamente com coroutines do Kotlin.\nCriando tabelas e inserindo dados import org.jetbrains.exposed.sql.r2dbc.suspendTransaction import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.insert import org.jetbrains.exposed.sql.batchInsert suspend fun inicializarBanco() { suspendTransaction(db = database) { SchemaUtils.create(Desenvolvedores, Projetos) } } suspend fun inserirDesenvolvedores() { suspendTransaction(db = database) { // Inserção individual Desenvolvedores.insert { it[nome] = \u0026#34;Ana Silva\u0026#34; it[linguagem] = \u0026#34;Kotlin\u0026#34; it[senioridade] = \u0026#34;senior\u0026#34; it[salario] = 22000.toBigDecimal() } // Inserção em lote — mais eficiente val devs = listOf( Triple(\u0026#34;Carlos Lima\u0026#34;, \u0026#34;pleno\u0026#34;, 12000), Triple(\u0026#34;Maria Santos\u0026#34;, \u0026#34;junior\u0026#34;, 5500), Triple(\u0026#34;Pedro Costa\u0026#34;, \u0026#34;senior\u0026#34;, 20000), ) Desenvolvedores.batchInsert(devs) { (nome, nivel, sal) -\u0026gt; this[Desenvolvedores.nome] = nome this[Desenvolvedores.senioridade] = nivel this[Desenvolvedores.salario] = sal.toBigDecimal() } } } Consultas reativas import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.andWhere suspend fun buscarDevsSenior(): List\u0026lt;String\u0026gt; { return suspendTransaction(db = database) { Desenvolvedores .selectAll() .where { Desenvolvedores.senioridade eq \u0026#34;senior\u0026#34; } .andWhere { Desenvolvedores.salario greaterEq 15000.toBigDecimal() } .map { row -\u0026gt; \u0026#34;${row[Desenvolvedores.nome]} - R$ ${row[Desenvolvedores.salario]}\u0026#34; } } } suspend fun buscarDevsComProjetos(): List\u0026lt;Pair\u0026lt;String, String\u0026gt;\u0026gt; { return suspendTransaction(db = database) { (Desenvolvedores innerJoin Projetos) .selectAll() .where { Projetos.ativo eq true } .map { row -\u0026gt; row[Desenvolvedores.nome] to row[Projetos.nome] } } } A diferença principal para o JDBC é o uso de suspendTransaction em vez de transaction. O código interno é praticamente idêntico.\nAtualização e exclusão import org.jetbrains.exposed.sql.update import org.jetbrains.exposed.sql.deleteWhere import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq suspend fun promoverDev(nome: String, novoSalario: Int) { suspendTransaction(db = database) { Desenvolvedores.update( where = { Desenvolvedores.nome eq nome } ) { it[senioridade] = \u0026#34;senior\u0026#34; it[salario] = novoSalario.toBigDecimal() } } } suspend fun removerDevsInativos() { suspendTransaction(db = database) { // Remove projetos inativos primeiro (integridade referencial) Projetos.deleteWhere { Projetos.ativo eq false } } } Integração com Spring Boot O Exposed 1.0 trouxe melhorias significativas para quem usa Spring Boot com Kotlin. Uma das mais impactantes é que agora você pode usar a DSL do Exposed diretamente em métodos anotados com @Transactional, sem precisar envolver o código em blocos transaction { } explícitos:\nimport org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import org.jetbrains.exposed.sql.selectAll @Service class DesenvolvedorService { @Transactional(readOnly = true) fun listarTodos(): List\u0026lt;DesenvolvedorDTO\u0026gt; { return Desenvolvedores .selectAll() .map { row -\u0026gt; DesenvolvedorDTO( id = row[Desenvolvedores.id], nome = row[Desenvolvedores.nome], senioridade = row[Desenvolvedores.senioridade], salario = row[Desenvolvedores.salario] ) } } @Transactional fun atualizarSalario(id: Int, novoSalario: Int) { Desenvolvedores.update( where = { Desenvolvedores.id eq id } ) { it[salario] = novoSalario.toBigDecimal() } } } data class DesenvolvedorDTO( val id: Int, val nome: String, val senioridade: String, val salario: java.math.BigDecimal ) O Exposed 1.0 também suporta GraalVM native image, o que permite compilar seu aplicativo Spring Boot com Exposed para uma imagem nativa com startup em milissegundos.\nMigrando da versão 0.x para 1.0 Se você já usa o Exposed em projetos existentes, a migração é tranquila na maioria dos casos. Os principais pontos de atenção:\n// ANTES (0.61.0) - pacote antigo import org.jetbrains.exposed.sql.transactions.transaction // DEPOIS (1.0.0) - mesmo pacote, mas para R2DBC use: import org.jetbrains.exposed.sql.r2dbc.suspendTransaction // ANTES - Coordenadas Maven antigas // org.jetbrains.exposed:exposed-core:0.61.0 // DEPOIS - Coordenadas Maven novas // org.jetbrains.exposed:exposed-core:1.0.0 // org.jetbrains.exposed:exposed-r2dbc:1.0.0 (novo módulo) A JetBrains disponibiliza um guia de migração completo na documentação oficial.\nJDBC vs R2DBC: quando usar cada um? Essa é uma dúvida comum. Aqui vai um resumo prático:\nCenário Recomendação API REST com Spring Boot JDBC (mais simples, suficiente para a maioria dos casos) API com alta concorrência R2DBC (menos threads bloqueadas) Aplicação com Ktor e coroutines R2DBC (integração natural com suspend) Projeto legado migrando para Kotlin JDBC (compatibilidade com drivers existentes) Microserviços reativos R2DBC (alinhado com arquitetura reativa) Se você trabalha com microserviços em Kotlin, o R2DBC é especialmente interessante por não bloquear threads durante I/O de banco.\nPerformance: JDBC vs R2DBC Em testes internos da JetBrains, o R2DBC mostrou vantagens em cenários de alta concorrência:\n// Exemplo: processamento paralelo com R2DBC e coroutines import kotlinx.coroutines.* suspend fun processarEmParalelo(ids: List\u0026lt;Int\u0026gt;) = coroutineScope { ids.map { id -\u0026gt; async { suspendTransaction(db = database) { Desenvolvedores .selectAll() .where { Desenvolvedores.id eq id } .firstOrNull() } } }.awaitAll() } Com JDBC tradicional, cada consulta paralela ocuparia uma thread do pool. Com R2DBC e coroutines, as mesmas operações compartilham um número muito menor de threads, liberando recursos para outras tarefas.\nPara mais sobre concorrência em Kotlin, confira nosso guia completo de coroutines e o artigo sobre Kotlin Flow.\nConclusão O Exposed 1.0 é um marco importante para o ecossistema Kotlin. Com API estável, suporte a R2DBC e integração melhorada com Spring Boot, ele se consolida como a opção mais idiomática para acesso a banco de dados em Kotlin — sem a complexidade do Hibernate e com toda a segurança de tipos que a linguagem oferece.\nSe você está começando com backend em Kotlin, nosso guia de REST APIs é um ótimo ponto de partida. Para quem já trabalha com Exposed, a documentação oficial da versão 1.0 e o repositório no GitHub têm tudo que você precisa para migrar.\nSe você trabalha com backend em múltiplas linguagens, vale comparar como ORMs funcionam em outros ecossistemas: Go usa GORM e sqlx com uma abordagem mais explícita, enquanto Python tem SQLAlchemy como referência. O Exposed combina o melhor dos dois mundos: type safety forte com APIs expressivas.\nQuer acompanhar o mercado Kotlin no Brasil? Veja as vagas abertas e os salários por senioridade.\n","permalink":"https://kotlin.dev.br/blog/exposed-1-0-r2dbc-kotlin-2026/","summary":"\u003cp\u003eDepois de anos em desenvolvimento, o \u003cstrong\u003eExposed 1.0\u003c/strong\u003e finalmente chegou — e é uma release que muda o jogo para quem trabalha com banco de dados em Kotlin. O framework SQL da JetBrains agora oferece \u003cstrong\u003esuporte oficial a R2DBC\u003c/strong\u003e, uma \u003cstrong\u003eAPI estável com garantia de compatibilidade\u003c/strong\u003e, e melhorias significativas de performance.\u003c/p\u003e\n\u003cp\u003eSe você já conhece o Exposed pelo nosso \u003ca href=\"/blog/kotlin-exposed-orm-framework-sql/\"\u003etutorial completo do framework\u003c/a\u003e, prepare-se: a versão 1.0 traz tudo que a comunidade vinha pedindo. Vamos ver o que mudou na prática.\u003c/p\u003e","title":"Exposed 1.0: ORM Kotlin com R2DBC e API Estável | Kotlin Brasil"},{"content":"Se você acompanha o ecossistema Kotlin, já percebeu que a JetBrains está investindo pesado em inteligência artificial. E a peça central dessa estratégia para devs Kotlin é o Koog — um framework open-source para construir agentes de IA diretamente em Kotlin, com suporte a múltiplas plataformas, tolerância a falhas e integração nativa com Spring Boot e Ktor.\nNeste artigo, vamos explorar o que é o Koog, como funciona, e criar exemplos práticos para você sair daqui pronto para montar seu primeiro agente.\nO que é o Koog? O Koog é um framework JVM criado pela JetBrains para construir agentes de IA previsíveis, tolerantes a falhas e prontos para produção. Diferente de SDKs simples que apenas fazem chamadas a APIs de LLMs, o Koog oferece uma arquitetura completa para orquestrar agentes que:\nExecutam ferramentas (tools) para interagir com sistemas externos Mantêm contexto em conversas longas com compressão inteligente de histórico Se recuperam de falhas com retries automáticos e persistência de estado Rodam em múltiplas plataformas via Kotlin Multiplatform (JVM, Android, iOS, WasmJS, browser) A versão mais recente é a 0.7.3, lançada em março de 2026, e já suporta provedores como OpenAI, Anthropic, Google, DeepSeek, Ollama e até Amazon Bedrock.\nSe você já leu nosso artigo sobre Kotlin e IA/Machine Learning, o Koog é a evolução natural desse cenário — agora com um framework oficial da JetBrains.\nConfigurando o projeto O setup é simples. Adicione a dependência no seu build.gradle.kts:\n// build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.3.20\u0026#34; } repositories { mavenCentral() } dependencies { implementation(\u0026#34;ai.koog:koog-agents:0.7.3\u0026#34;) } O Koog exige JDK 17+ e Kotlin 2.3.10+. Se você ainda está em versões anteriores, vale conferir nosso guia de novidades do Kotlin 2.3.20.\nCriando seu primeiro agente O exemplo mais básico é um agente que responde perguntas usando um LLM:\nimport ai.koog.agents.core.agent.AIAgent import ai.koog.agents.core.tools.simpleOpenAIExecutor import ai.koog.agents.ext.model.OpenAIModels import kotlinx.coroutines.runBlocking fun main() = runBlocking { val apiKey = System.getenv(\u0026#34;OPENAI_API_KEY\u0026#34;) val agente = AIAgent( promptExecutor = simpleOpenAIExecutor(apiKey), systemPrompt = \u0026#34;Você é um assistente especializado em Kotlin. \u0026#34; + \u0026#34;Responda em português brasileiro de forma clara e concisa.\u0026#34;, llmModel = OpenAIModels.Chat.GPT4o ) val resposta = agente.run(\u0026#34;Qual a diferença entre val e var em Kotlin?\u0026#34;) println(resposta) } Esse é o \u0026ldquo;Hello World\u0026rdquo; do Koog. O AIAgent recebe um executor (que faz a comunicação com o LLM), um system prompt e o modelo a ser usado. Se você quiser usar Anthropic ou outro provedor, basta trocar o executor.\nCriando Tools personalizadas O verdadeiro poder dos agentes está nas tools — funções que o agente pode chamar para interagir com o mundo externo. O Koog oferece duas abordagens para definir tools: baseada em anotações e baseada em classes.\nTool com anotações A forma mais simples usa a anotação @Tool:\nimport ai.koog.agents.core.tools.annotations.Tool import ai.koog.agents.core.tools.annotations.ToolParam @Tool(\u0026#34;buscar_salario\u0026#34;, \u0026#34;Busca o salário médio de um cargo em Kotlin no Brasil\u0026#34;) fun buscarSalario( @ToolParam(\u0026#34;cargo\u0026#34;, \u0026#34;O cargo a ser pesquisado, ex: junior, pleno, senior\u0026#34;) cargo: String ): String { val salarios = mapOf( \u0026#34;junior\u0026#34; to \u0026#34;R$ 4.500 - R$ 7.000\u0026#34;, \u0026#34;pleno\u0026#34; to \u0026#34;R$ 8.000 - R$ 14.000\u0026#34;, \u0026#34;senior\u0026#34; to \u0026#34;R$ 15.000 - R$ 25.000\u0026#34; ) return salarios[cargo.lowercase()] ?: \u0026#34;Cargo não encontrado. Tente: junior, pleno ou senior.\u0026#34; } Quando o agente percebe que precisa buscar informações de salário, ele automaticamente chama essa tool. Se você se interessa por dados de carreira, temos conteúdos detalhados sobre salários de dev Kotlin e mercado de trabalho.\nTool baseada em classe Para tools mais complexas com estado ou dependências:\nimport ai.koog.agents.core.tools.Tool import ai.koog.agents.core.tools.ToolDescriptor import ai.koog.agents.core.tools.ToolParameter class BuscaGlossarioTool : Tool { override val descriptor = ToolDescriptor( name = \u0026#34;buscar_glossario\u0026#34;, description = \u0026#34;Busca a definição de um termo Kotlin no glossário\u0026#34;, parameters = listOf( ToolParameter( name = \u0026#34;termo\u0026#34;, description = \u0026#34;O termo Kotlin a ser pesquisado\u0026#34;, type = \u0026#34;string\u0026#34;, required = true ) ) ) private val glossario = mapOf( \u0026#34;coroutine\u0026#34; to \u0026#34;Mecanismo de concorrência leve do Kotlin para programação assíncrona\u0026#34;, \u0026#34;sealed class\u0026#34; to \u0026#34;Classe que restringe hierarquia de herança a um conjunto finito\u0026#34;, \u0026#34;data class\u0026#34; to \u0026#34;Classe que gera automaticamente equals, hashCode, toString e copy\u0026#34;, \u0026#34;flow\u0026#34; to \u0026#34;Stream reativo frio do Kotlin para emitir valores assíncronos\u0026#34;, \u0026#34;suspend\u0026#34; to \u0026#34;Modificador que marca uma função como suspendível para uso com coroutines\u0026#34; ) override suspend fun execute(arguments: Map\u0026lt;String, String\u0026gt;): String { val termo = arguments[\u0026#34;termo\u0026#34;]?.lowercase() ?: return \u0026#34;Termo não informado\u0026#34; return glossario[termo] ?: \u0026#34;Termo \u0026#39;$termo\u0026#39; não encontrado. Consulte o glossário completo.\u0026#34; } } Nosso glossário Kotlin tem mais de 50 termos — imagine integrar isso a um agente que responde dúvidas de estudantes!\nAgentes com fluxo baseado em grafo Além do modo funcional, o Koog permite definir fluxos de agente como um grafo de estados. Isso é útil para workflows mais complexos onde o agente precisa tomar decisões em sequência:\nimport ai.koog.agents.core.agent.AIAgent import ai.koog.agents.core.dsl.builder.forwardTo import ai.koog.agents.core.dsl.builder.strategy val estrategia = strategy(\u0026#34;analise-codigo\u0026#34;) { val analisar by node { prompt(\u0026#34;Analise este código Kotlin e identifique problemas de performance.\u0026#34;) } val sugerir by node { prompt(\u0026#34;Sugira melhorias com exemplos de código corrigido.\u0026#34;) } val revisar by node { prompt(\u0026#34;Revise as sugestões e dê uma nota de 1 a 10 para o código.\u0026#34;) } edge(analisar forwardTo sugerir) edge(sugerir forwardTo revisar) entryNode = analisar exitNode = revisar } Esse padrão é especialmente poderoso para criar pipelines de code review, análise de dados ou automação de DevOps. Se você trabalha com CI/CD em Kotlin, vale conferir nosso artigo sobre Kotlin e DevOps.\nIntegração com Spring Boot O Koog se integra nativamente com Spring Boot, o que facilita expor agentes como endpoints REST:\nimport ai.koog.agents.spring.AgentService import org.springframework.web.bind.annotation.* @RestController @RequestMapping(\u0026#34;/api/agente\u0026#34;) class AgenteKotlinController( private val agentService: AgentService ) { @PostMapping(\u0026#34;/perguntar\u0026#34;) suspend fun perguntar(@RequestBody pergunta: PerguntaRequest): RespostaDTO { val resposta = agentService.run(pergunta.texto) return RespostaDTO(resposta = resposta) } } data class PerguntaRequest(val texto: String) data class RespostaDTO(val resposta: String) Se você já usa Spring Boot com Kotlin, adicionar um agente de IA ao seu backend é questão de configurar o Koog como um bean e injetá-lo nos seus controllers.\nIntegração com Ktor Para quem prefere o Ktor, o Koog oferece um plugin dedicado:\nimport ai.koog.agents.ktor.koogAgent import io.ktor.server.application.* import io.ktor.server.engine.* import io.ktor.server.netty.* import io.ktor.server.routing.* import io.ktor.server.request.* import io.ktor.server.response.* fun main() { embeddedServer(Netty, port = 8080) { install(KoogAgent) { apiKey = System.getenv(\u0026#34;OPENAI_API_KEY\u0026#34;) systemPrompt = \u0026#34;Assistente Kotlin em português\u0026#34; } routing { post(\u0026#34;/chat\u0026#34;) { val input = call.receiveText() val resposta = call.application.koogAgent.run(input) call.respondText(resposta) } } }.start(wait = true) } Provedores de LLM suportados O Koog não te prende a um único provedor. Atualmente, ele suporta:\nProvedor Modelos OpenAI GPT-4o, GPT-4o-mini, o1, o3 Anthropic Claude 3.5 Sonnet, Claude 4 Google Gemini Pro, Gemini Ultra DeepSeek DeepSeek-V3, DeepSeek-R1 Ollama Qualquer modelo local Amazon Bedrock Modelos disponíveis na AWS OpenRouter Roteamento multi-provedor Isso significa que você pode começar testando com Ollama localmente e depois migrar para OpenAI ou Anthropic em produção sem mudar a lógica do agente.\nKotlin Multiplatform: agentes em todo lugar Uma das maiores vantagens do Koog é o suporte a Kotlin Multiplatform. Você pode executar agentes em:\nBackend (JVM com Spring Boot ou Ktor) Android (diretamente no app) iOS (via compilação Kotlin/Native) Browser (via Kotlin/WasmJS) Isso abre possibilidades como agentes embarcados em apps mobile que funcionam offline com modelos locais via Ollama.\nQuando usar o Koog? O Koog faz sentido quando você precisa de mais do que uma simples chamada de API para um LLM. Cenários ideais incluem:\nChatbots empresariais com acesso a bases de dados internas Automação de workflows com múltiplas etapas e decisões Assistentes de código que executam análise estática e sugerem melhorias Pipelines de dados com agentes que coletam, processam e relatam informações Apps mobile com IA embarcada via Kotlin Multiplatform Conclusão O Koog posiciona o Kotlin como uma linguagem de primeira classe para desenvolvimento de agentes de IA. Com suporte a múltiplos provedores, integração nativa com Spring Boot e Ktor, e a flexibilidade do Kotlin Multiplatform, ele remove as barreiras para quem quer construir aplicações inteligentes sem sair do ecossistema Kotlin.\nSe você está começando com Kotlin, confira nosso guia completo da linguagem. Para quem já domina o básico e quer explorar o backend, nossos guias de Ktor e Spring Boot são ótimos pontos de partida antes de mergulhar no Koog.\nA documentação oficial está em docs.koog.ai e o código-fonte no GitHub da JetBrains. No mundo de IA, Python ainda domina com LangChain e CrewAI, mas o Koog traz a vantagem de type safety e coroutines nativas — ideal para times que já vivem no ecossistema Kotlin e não querem manter uma stack separada em Python só para IA.\nTem interesse em carreira Kotlin? Confira nossas páginas de vagas remotas e como se tornar dev Kotlin.\n","permalink":"https://kotlin.dev.br/blog/koog-kotlin-agentes-ia-2026/","summary":"\u003cp\u003eSe você acompanha o ecossistema Kotlin, já percebeu que a JetBrains está investindo pesado em inteligência artificial. E a peça central dessa estratégia para devs Kotlin é o \u003cstrong\u003eKoog\u003c/strong\u003e — um framework open-source para construir \u003cstrong\u003eagentes de IA\u003c/strong\u003e diretamente em Kotlin, com suporte a múltiplas plataformas, tolerância a falhas e integração nativa com Spring Boot e Ktor.\u003c/p\u003e\n\u003cp\u003eNeste artigo, vamos explorar o que é o Koog, como funciona, e criar exemplos práticos para você sair daqui pronto para montar seu primeiro agente.\u003c/p\u003e","title":"Koog: Framework Kotlin para Agentes de IA da JetBrains | Kotlin Brasil"},{"content":"Se você trabalha com dados e sempre associou notebooks interativos ao Python e Jupyter, é hora de conhecer o Kotlin Notebook. Integrado ao IntelliJ IDEA e com suporte a bibliotecas poderosas como DataFrame e Kandy, o Kotlin Notebook está se consolidando como uma alternativa real para análise de dados — com a vantagem de tipagem estática e toda a expressividade do Kotlin.\nCom as novidades de 2026 e palestras dedicadas na KotlinConf 2026 e IntelliJ IDEA Conf, a ferramenta ganha cada vez mais atenção. Neste artigo, você vai aprender o que é, como funciona e como começar a usar na prática.\nO que é o Kotlin Notebook? O Kotlin Notebook é um ambiente de desenvolvimento interativo baseado em células, integrado diretamente ao IntelliJ IDEA. Ele permite:\nExecutar código Kotlin em células com resultado imediato Misturar código, texto em Markdown e visualizações no mesmo documento Explorar dados com feedback instantâneo Exportar como .ipynb (compatível com Jupyter) O Kotlin Notebook é baseado no Kotlin Kernel para Jupyter Notebooks, o que garante compatibilidade com Jupyter, Datalore e outras ferramentas do ecossistema.\nSetup: zero configuração A melhor parte? O plugin do Kotlin Notebook já vem bundled e habilitado no IntelliJ IDEA. Basta criar um novo arquivo .ipynb e começar a escrever código Kotlin. Não precisa instalar interpretadores Python, ambientes virtuais ou dependências externas.\nCarregando e explorando dados com DataFrame A biblioteca Kotlin DataFrame permite carregar, filtrar, transformar e analisar dados estruturados com uma API tipada e idiomática.\nImportando a dependência Em uma célula do notebook, basta usar a anotação %use:\n%use dataframe Lendo um arquivo CSV val dados = DataFrame.read(\u0026#34;vendas-2026.csv\u0026#34;) dados.head(5) A saída aparece como uma tabela formatada diretamente no notebook, semelhante a um pandas.DataFrame no Python.\nFiltrando e transformando dados // Filtrando vendas acima de R$ 1000 val vendasAltas = dados .filter { \u0026#34;valor\u0026#34;\u0026lt;Double\u0026gt;() \u0026gt; 1000.0 } .sortByDesc(\u0026#34;valor\u0026#34;) vendasAltas.head(10) Agrupando e agregando // Total de vendas por região val totalPorRegiao = dados .groupBy(\u0026#34;regiao\u0026#34;) .aggregate { sum(\u0026#34;valor\u0026#34;) into \u0026#34;total_vendas\u0026#34; count() into \u0026#34;quantidade\u0026#34; } .sortByDesc(\u0026#34;total_vendas\u0026#34;) totalPorRegiao A grande vantagem sobre Python é que o DataFrame do Kotlin gera tipos automaticamente a partir dos dados. Quando você carrega um CSV, as colunas viram propriedades tipadas — erros de nome de coluna são pegos em tempo de compilação, não em runtime.\nConectando com bancos de dados O DataFrame também suporta leitura direta de SQL:\n%use dataframe val conexao = \u0026#34;jdbc:postgresql://localhost:5432/meubanco\u0026#34; val query = \u0026#34;SELECT nome, departamento, salario FROM funcionarios\u0026#34; val funcionarios = DataFrame.readSqlQuery(conexao, query) funcionarios .filter { \u0026#34;salario\u0026#34;\u0026lt;Double\u0026gt;() \u0026gt; 8000.0 } .groupBy(\u0026#34;departamento\u0026#34;) .aggregate { mean(\u0026#34;salario\u0026#34;) into \u0026#34;salario_medio\u0026#34; count() into \u0026#34;total\u0026#34; } Se você já trabalha com bancos de dados em Kotlin usando Exposed, o DataFrame complementa como ferramenta de análise exploratória.\nVisualizando dados com Kandy O Kandy é a biblioteca de visualização oficial do ecossistema Kotlin, construída sobre o LetsPlot. Ela oferece uma DSL type-safe para criar gráficos diretamente no notebook.\nImportando o Kandy %use kandy Gráfico de barras val regioes = listOf(\u0026#34;Sudeste\u0026#34;, \u0026#34;Sul\u0026#34;, \u0026#34;Nordeste\u0026#34;, \u0026#34;Centro-Oeste\u0026#34;, \u0026#34;Norte\u0026#34;) val vendas = listOf(45000, 32000, 28000, 18000, 12000) plot { bars { x(regioes) { axis.name = \u0026#34;Região\u0026#34; } y(vendas) { axis.name = \u0026#34;Vendas (R$)\u0026#34; } fillColor = Color.hex(\u0026#34;#7F52FF\u0026#34;) // Roxo Kotlin } layout.title = \u0026#34;Vendas por Região — 2026\u0026#34; } Gráfico de linhas com séries temporais val meses = listOf(\u0026#34;Jan\u0026#34;, \u0026#34;Fev\u0026#34;, \u0026#34;Mar\u0026#34;, \u0026#34;Abr\u0026#34;, \u0026#34;Mai\u0026#34;, \u0026#34;Jun\u0026#34;) val receita = listOf(120000, 135000, 128000, 142000, 155000, 148000) val custos = listOf(95000, 98000, 102000, 99000, 105000, 108000) plot { line { x(meses) { axis.name = \u0026#34;Mês\u0026#34; } y(receita) { axis.name = \u0026#34;Valor (R$)\u0026#34; } color = Color.hex(\u0026#34;#7F52FF\u0026#34;) width = 2.5 } line { x(meses) y(custos) color = Color.hex(\u0026#34;#E87D3E\u0026#34;) width = 2.5 } layout { title = \u0026#34;Receita vs Custos — 1º Semestre 2026\u0026#34; size = 800 to 400 } } Gráfico de dispersão val experiencia = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) val salarios = listOf(4500, 5200, 6100, 7800, 8500, 9200, 10500, 11800, 13000, 15000) plot { points { x(experiencia) { axis.name = \u0026#34;Anos de Experiência\u0026#34; } y(salarios) { axis.name = \u0026#34;Salário (R$)\u0026#34; } size = 5.0 color = Color.hex(\u0026#34;#7F52FF\u0026#34;) } layout.title = \u0026#34;Experiência vs Salário — Devs Kotlin no Brasil\u0026#34; } Se você se interessa pela relação entre experiência e salário, temos artigos detalhados sobre salários de dev Kotlin e mercado de trabalho.\nCasos de uso práticos O Kotlin Notebook não é só para data scientists. Veja onde ele brilha:\n1. Prototipagem rápida de APIs Testar endpoints antes de integrar no projeto principal:\n@file:DependsOn(\u0026#34;io.ktor:ktor-client-core:3.1.2\u0026#34;) @file:DependsOn(\u0026#34;io.ktor:ktor-client-cio:3.1.2\u0026#34;) @file:DependsOn(\u0026#34;io.ktor:ktor-client-content-negotiation:3.1.2\u0026#34;) @file:DependsOn(\u0026#34;io.ktor:ktor-serialization-kotlinx-json:3.1.2\u0026#34;) import io.ktor.client.* import io.ktor.client.request.* import io.ktor.client.statement.* val client = HttpClient() val response = client.get(\u0026#34;https://api.github.com/repos/JetBrains/kotlin\u0026#34;) println(response.bodyAsText().take(500)) Se você trabalha com Ktor, o notebook é perfeito para experimentação rápida.\n2. Análise de logs e métricas Carregar logs de produção e analisar padrões:\n%use dataframe val logs = DataFrame.read(\u0026#34;app-logs-2026-04.csv\u0026#34;) // Erros por hora do dia val errosPorHora = logs .filter { \u0026#34;level\u0026#34;\u0026lt;String\u0026gt;() == \u0026#34;ERROR\u0026#34; } .groupBy(\u0026#34;hora\u0026#34;) .count() .sortBy(\u0026#34;hora\u0026#34;) errosPorHora 3. Documentação executável Combinar Markdown e código para criar documentação que realmente roda:\n## Exemplo de uso do nosso SDK O trecho abaixo mostra como autenticar e buscar dados: val sdk = MeuSDK(apiKey = \u0026#34;demo-key\u0026#34;) val resultado = sdk.buscarDados(filtro = \u0026#34;ativo\u0026#34;) resultado.forEach { println(it) } 4. Preparação de dados para Machine Learning Se você está explorando Kotlin para IA e Machine Learning, o Notebook é ideal para a etapa de preparação de dados — limpeza, normalização e feature engineering.\nKotlin Notebook vs Jupyter com Python Aspecto Kotlin Notebook Jupyter (Python) Tipagem Estática (erros em compile time) Dinâmica (erros em runtime) IDE IntelliJ IDEA nativo Navegador ou VS Code Autocompletar Completo, com tipos Limitado Performance JVM (rápido para processamento) Interpretado Ecossistema de dados DataFrame + Kandy pandas + matplotlib/seaborn Interoperabilidade Java, Kotlin, KMP Python Formato .ipynb compatível .ipynb nativo Para quem já programa em Kotlin e precisa analisar dados, o Kotlin Notebook elimina a troca de contexto para Python. Você usa a mesma linguagem do backend, do Android e do Compose Multiplatform.\nDicas para começar Atualize o IntelliJ IDEA para a versão 2025.1 ou superior Crie um novo Kotlin Notebook: File → New → Kotlin Notebook Use %use para importar bibliotecas: %use dataframe, %use kandy Explore dados reais: comece com um CSV pequeno do seu projeto Exporte como .ipynb para compartilhar com colegas que usam Jupyter Recursos e próximos passos O Kotlin Notebook está evoluindo rapidamente. Na KotlinConf 2026 (maio, em Munique), haverá palestras dedicadas sobre análise de dados com Kotlin, incluindo workshops práticos com DataFrame e Kandy.\nPara aprofundar, confira estes conteúdos relacionados:\nKotlin para IA e Machine Learning Melhores bibliotecas Kotlin Kotlin DSL: criando APIs expressivas Coroutines em Kotlin — útil para processamento assíncrono de dados Extension functions — base para as DSLs do DataFrame e Kandy Kotlin 2.4.0 Beta1: todas as novidades Conclusão O Kotlin Notebook transforma o IntelliJ IDEA em um ambiente completo para análise de dados, prototipagem e documentação interativa. Com DataFrame para manipulação de dados e Kandy para visualização, você tem um stack 100% Kotlin — sem precisar alternar para Python.\nSe você é dev Kotlin e precisa explorar dados, gerar relatórios ou prototipar rapidamente, o Notebook é uma ferramenta que vale conhecer. Comece com um CSV do seu projeto e veja como a tipagem estática e o autocompletar do IntelliJ IDEA fazem diferença na produtividade.\nEmbora Python com Jupyter ainda domine data science, o Kotlin Notebook oferece vantagens únicas para quem já trabalha no ecossistema JVM — especialmente a tipagem estática e o autocomplete inteligente do IntelliJ.\nPara mais conteúdo sobre o ecossistema Kotlin em português, explore nosso glossário, tutoriais e guias completos.\n","permalink":"https://kotlin.dev.br/blog/kotlin-notebook-data-science-2026/","summary":"\u003cp\u003eSe você trabalha com dados e sempre associou notebooks interativos ao Python e Jupyter, é hora de conhecer o \u003cstrong\u003eKotlin Notebook\u003c/strong\u003e. Integrado ao IntelliJ IDEA e com suporte a bibliotecas poderosas como \u003cstrong\u003eDataFrame\u003c/strong\u003e e \u003cstrong\u003eKandy\u003c/strong\u003e, o Kotlin Notebook está se consolidando como uma alternativa real para análise de dados — com a vantagem de tipagem estática e toda a expressividade do Kotlin.\u003c/p\u003e\n\u003cp\u003eCom as novidades de 2026 e palestras dedicadas na \u003ca href=\"https://kotlinconf.com/\"\u003eKotlinConf 2026\u003c/a\u003e e IntelliJ IDEA Conf, a ferramenta ganha cada vez mais atenção. Neste artigo, você vai aprender o que é, como funciona e como começar a usar na prática.\u003c/p\u003e","title":"Kotlin Notebook para Data Science: Guia Prático em 2026 | Kotlin Brasil"},{"content":"O ecossistema Kotlin continua evoluindo em ritmo acelerado. Com o lançamento do Kotlin 2.4.0-Beta1 em 31 de março de 2026, a JetBrains entrega um pacote de novidades que afeta desde a escrita de código no dia a dia até a integração com plataformas nativas como iOS e JVM. Neste artigo, vamos explorar os principais recursos dessa release, com exemplos práticos para você já ir testando.\nSe você ainda está se atualizando com as versões anteriores, vale conferir nosso conteúdo sobre Kotlin 2.1 e suas novidades em 2026 e também o Kotlin 2.3.20.\nContext Parameters agora são Stable Essa é, sem dúvida, a novidade mais aguardada. Os context parameters, que vinham em preview desde o Kotlin 2.2, finalmente atingiram o status estável na 2.4.0. Isso significa que você pode usá-los em produção sem precisar de opt-in experimental.\nSe você já leu nosso guia sobre Context Receivers e Context Parameters, sabe que essa feature permite declarar dependências implícitas de contexto para funções e propriedades. A grande vantagem é eliminar a passagem manual de parâmetros que raramente mudam entre chamadas.\n// Context parameter estável no Kotlin 2.4.0 context(logger: Logger) fun processarPedido(pedido: Pedido) { logger.info(\u0026#34;Processando pedido ${pedido.id}\u0026#34;) // lógica de negócio aqui logger.info(\u0026#34;Pedido ${pedido.id} processado com sucesso\u0026#34;) } // Chamando a função — o contexto é fornecido implicitamente fun main() { val logger = Logger.getLogger(\u0026#34;App\u0026#34;) with(logger) { processarPedido(Pedido(id = 42)) } } A diferença principal em relação aos antigos context receivers é que agora cada contexto precisa de um nome explícito. Em vez de context(Logger), você escreve context(logger: Logger) e usa logger.info() no corpo da função. Isso torna o código mais legível e reduz ambiguidades.\nContext Arguments explícitos (experimental) A 2.4.0-Beta1 também introduz, em modo experimental, os explicit context arguments. Eles resolvem situações onde existem overloads que diferem apenas pelo tipo de contexto:\nclass EmailSender class SmsSender context(emailSender: EmailSender) fun enviarNotificacao() { println(\u0026#34;Notificação enviada por e-mail\u0026#34;) } context(smsSender: SmsSender) fun enviarNotificacao() { println(\u0026#34;Notificação enviada por SMS\u0026#34;) } context(email: EmailSender, sms: SmsSender) fun notificarUsuario() { // Especificando qual contexto usar explicitamente enviarNotificacao(emailSender = email) // Usa o overload de EmailSender enviarNotificacao(smsSender = sms) // Usa o overload de SmsSender } Se você trabalha com DSLs em Kotlin ou injeção de dependência, os context parameters estáveis abrem portas para APIs ainda mais expressivas.\nImportação de Swift Packages no Kotlin/Native Outra novidade de peso: projetos Kotlin Multiplatform agora podem declarar Swift packages como dependências diretamente no build.gradle.kts. Antes, a integração com bibliotecas iOS dependia exclusivamente de CocoaPods ou frameworks pré-compilados. Com o Swift Package Manager (SwiftPM) agora suportado, a integração fica muito mais natural.\n// build.gradle.kts kotlin { swiftPMDependencies { swiftPackage( url = url(\u0026#34;https://github.com/firebase/firebase-ios-sdk.git\u0026#34;), version = from(\u0026#34;12.11.0\u0026#34;), products = listOf( product(\u0026#34;FirebaseAI\u0026#34;), product(\u0026#34;FirebaseAnalytics\u0026#34;), ) ) } } Para quem desenvolve apps multiplataforma, isso elimina uma grande barreira na integração com o ecossistema iOS. Se você está começando com KMP, veja nosso guia de Kotlin Multiplatform Mobile e o tutorial prático de KMP.\nSuporte oficial a Java 26 O compilador Kotlin agora consegue gerar bytecode compatível com Java 26. Isso é essencial para projetos que rodam em JVMs mais recentes e querem aproveitar as otimizações de runtime mais novas.\nPara configurar no Gradle:\n// build.gradle.kts kotlin { jvmToolchain(26) } Se você trabalha com Spring Boot e Kotlin ou microsserviços, o suporte a Java 26 garante que seu backend pode rodar na JVM mais atualizada sem restrições do compilador.\nNovas APIs na Standard Library A 2.4.0 traz duas adições práticas à stdlib:\nConversão de unsigned integers para BigInteger Agora você pode converter UInt e ULong diretamente para BigInteger, algo que fazia falta para cálculos com valores grandes:\nfun main() { val unsignedLong = Long.MAX_VALUE.toULong() + 1uL val unsignedInt = UInt.MAX_VALUE println(unsignedLong.toBigInteger()) // 9223372036854775808 println(unsignedInt.toBigInteger()) // 4294967295 } Verificação de ordenação em coleções Novas extension functions permitem checar se uma coleção está ordenada de forma declarativa:\ndata class Usuario(val nome: String, val idade: Int) fun main() { val numeros = listOf(1, 2, 3, 4) println(numeros.isSorted()) // true println(numeros.isSortedDescending()) // false val usuarios = listOf( Usuario(\u0026#34;Alice\u0026#34;, 24), Usuario(\u0026#34;Bruno\u0026#34;, 31), Usuario(\u0026#34;Carlos\u0026#34;, 29), ) println(usuarios.isSortedBy { it.idade }) // false } Essas funções simplificam validações que antes exigiam loops manuais ou comparações com zipWithNext. Se você quer aprofundar em collections do Kotlin, temos um tutorial completo.\nInlining consistente entre módulos A partir da 2.4.0, o intra-module inlining é habilitado por padrão para Kotlin/Native, Kotlin/JS e Kotlin/Wasm. Isso significa que funções inline declaradas no mesmo módulo são inlinadas durante a compilação do .klib, melhorando a performance de runtime.\nPara quem desenvolve bibliotecas Kotlin Multiplatform, essa mudança pode trazer ganhos de performance sem nenhuma alteração no código.\nAnotações em metadata por padrão O suporte a leitura e escrita de anotações nos metadados Kotlin agora vem habilitado por padrão na JVM. Isso beneficia processadores de anotações e frameworks como o KSP, que agora podem manipular anotações no nível de metadata sem depender de reflection.\nComo testar o Kotlin 2.4.0-Beta1 Para experimentar a Beta1 no seu projeto, atualize o plugin Kotlin no settings.gradle.kts:\n// settings.gradle.kts pluginManagement { plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.4.0-Beta1\u0026#34; } } E no build.gradle.kts:\nplugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.4.0-Beta1\u0026#34; } Atenção: por ser uma versão Beta, não é recomendada para produção. Use em branches de teste ou projetos experimentais. A versão estável 2.4.0 deve chegar nos próximos meses.\nConclusão O Kotlin 2.4.0-Beta1 consolida funcionalidades que estavam em preview e abre novas possibilidades — especialmente com context parameters estáveis e importação de Swift packages. Para times que mantêm projetos backend com Ktor ou apps Android, vale acompanhar de perto o caminho até a release estável.\nSe você quer se manter atualizado com o ecossistema Kotlin, confira também:\nTendências Kotlin 2026 Amper: novo build tool para Kotlin Compose Multiplatform 1.10.6 Glossário Kotlin para referência rápida de termos Ficou com dúvida sobre algum recurso? Acesse nosso FAQ ou explore nossos guias completos. Se você trabalha com múltiplas linguagens, compare como Rust evolui com seu sistema de editions e como Python aborda tipagem gradual — temas que dialogam diretamente com os context parameters e a evolução de tipos do Kotlin.\n","permalink":"https://kotlin.dev.br/blog/kotlin-2-4-0-beta-novidades-2026/","summary":"\u003cp\u003eO ecossistema Kotlin continua evoluindo em ritmo acelerado. Com o lançamento do \u003cstrong\u003eKotlin 2.4.0-Beta1\u003c/strong\u003e em 31 de março de 2026, a JetBrains entrega um pacote de novidades que afeta desde a escrita de código no dia a dia até a integração com plataformas nativas como iOS e JVM. Neste artigo, vamos explorar os principais recursos dessa release, com exemplos práticos para você já ir testando.\u003c/p\u003e\n\u003cp\u003eSe você ainda está se atualizando com as versões anteriores, vale conferir nosso conteúdo sobre \u003ca href=\"/blog/kotlin-21-novidades-2026/\"\u003eKotlin 2.1 e suas novidades em 2026\u003c/a\u003e e também o \u003ca href=\"/blog/kotlin-2-3-20-novidades/\"\u003eKotlin 2.3.20\u003c/a\u003e.\u003c/p\u003e","title":"Kotlin 2.4.0 Beta1: Novidades e Recursos em 2026 | Kotlin Brasil"},{"content":"O Compose Multiplatform 1.10.6 reforça uma percepção que ficou muito mais clara em 2026: compartilhar interface com Kotlin deixou de ser experimento para virar opção concreta em projetos reais. A página de releases do ecossistema AndroidX já mostra uma linha estável consistente para os principais artefatos do Compose, enquanto Material 3 e recursos adaptativos continuam amadurecendo.\nPara quem acompanha o avanço do Kotlin no mobile e no desktop, essa versão importa porque ela consolida um baseline confiável para times que querem reduzir fragmentação entre plataformas. Em vez de olhar apenas para demos, agora dá para falar sobre setup previsível, bibliotecas estáveis, navegação compartilhada, recursos comuns e estratégia de atualização.\nNeste artigo, vamos ver o que representa a versão 1.10.6, como ela conversa com o ecossistema Compose em 2026 e como estruturar um app Kotlin moderno usando UI compartilhada sem perder qualidade de experiência.\nPor que o Compose Multiplatform 1.10.6 merece atenção? A relevância desta versão não está apenas no número. O que chama atenção é o contexto:\nbibliotecas principais do Compose em canal estável; Material 3 também em trilha madura; evolução dos componentes adaptativos para múltiplos formatos de tela; melhor previsibilidade para times que precisam decidir se adotam shared UI agora ou depois. Em outras palavras, a conversa deixou de ser “será que isso funciona?” e passou a ser “em quais cenários isso já faz sentido para produção?”.\nSe você ainda está conhecendo a base do ecossistema, comece também pelo nosso artigo sobre Compose Multiplatform e UI compartilhada em 2026 e pelo guia de Kotlin Multiplatform Mobile.\nO que a release estável indica na prática? Quando uma linha do Compose aparece como estável, isso sinaliza maturidade operacional. Para times de produto, significa algumas coisas importantes:\n1. Menor risco de churn de API Você tende a sofrer menos com mudanças bruscas entre versões.\n2. Mais confiança para padronizar dependências Fica mais simples definir uma baseline para vários módulos, especialmente em apps que compartilham design system.\n3. Melhor alinhamento com Material 3 A maturidade do Material 3 é decisiva para apps que precisam manter experiência visual moderna em Android, desktop e eventualmente iOS.\n4. Adoção mais plausível em roadmap real Quando a pilha estável existe, o assunto sai do laboratório e entra na pauta do time de arquitetura.\nExemplo de configuração com Compose Multiplatform 1.10.6 Um setup inicial pode ficar assim:\nplugins { kotlin(\u0026#34;multiplatform\u0026#34;) version \u0026#34;2.3.20\u0026#34; id(\u0026#34;org.jetbrains.compose\u0026#34;) version \u0026#34;1.10.6\u0026#34; id(\u0026#34;com.android.application\u0026#34;) } kotlin { androidTarget() jvm(\u0026#34;desktop\u0026#34;) iosX64() iosArm64() iosSimulatorArm64() sourceSets { commonMain.dependencies { implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material3) implementation(compose.ui) implementation(compose.components.resources) } androidMain.dependencies { implementation(\u0026#34;androidx.activity:activity-compose:1.10.1\u0026#34;) } val desktopMain by getting { dependencies { implementation(compose.desktop.currentOs) } } } } Esse exemplo mostra um ponto importante: o Compose Multiplatform não vive isolado. Ele depende de um alinhamento saudável entre versão do Kotlin, plugin do Compose, dependências AndroidX e configuração de targets.\nRecursos compartilhados ficaram mais importantes Uma das dores clássicas de shared UI sempre foi lidar com strings, imagens, ícones e outros assets sem criar gambiarra. Com a evolução do ecossistema, o módulo compose.components.resources ficou muito mais relevante.\nimport androidx.compose.runtime.Composable import androidx.compose.material3.Text import org.jetbrains.compose.resources.stringResource @Composable fun SaudacaoScreen() { Text(text = stringResource(Res.string.bem_vindo)) } Quando esse tipo de recurso funciona de forma consistente, compartilhar UI passa a ser bem mais realista. O custo de manter duas ou três árvores de interface separadas começa a parecer menos justificável.\nMaterial 3 estável muda a conversa A estabilidade do Compose Material 3 pesa muito a favor da adoção. Na prática, ele oferece:\ncomponentes prontos alinhados ao design moderno do Android; tema consistente entre telas e plataformas; base melhor para design systems compartilhados; integração mais natural com responsividade e adaptação por tamanho de janela. Veja um exemplo simples de tela inicial compartilhada:\n@Composable fun DashboardScreen( totalProjetos: Int, onAbrirProjetos: () -\u0026gt; Unit, ) { Scaffold( topBar = { TopAppBar( title = { Text(\u0026#34;Painel Kotlin\u0026#34;) } ) } ) { padding -\u0026gt; Column( modifier = Modifier .fillMaxSize() .padding(padding) .padding(24.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { ElevatedCard { Column(modifier = Modifier.padding(20.dp)) { Text( text = \u0026#34;Projetos ativos\u0026#34;, style = MaterialTheme.typography.labelLarge ) Text( text = totalProjetos.toString(), style = MaterialTheme.typography.displaySmall ) } } Button(onClick = onAbrirProjetos) { Text(\u0026#34;Ver projetos\u0026#34;) } } } } Esse tipo de componente não resolve sozinho toda a experiência multiplataforma, mas reduz muito a quantidade de código duplicado necessária para entregar uma interface coerente.\nE a adaptação para vários formatos de tela? Outro ponto importante em 2026 é a evolução dos componentes adaptativos do Material 3. Em um cenário com celulares, tablets, foldables e desktop, não basta compartilhar UI; é preciso adaptar layout com inteligência.\n@Composable fun LayoutResponsivo( mostrarPainelDetalhes: Boolean, ) { BoxWithConstraints(modifier = Modifier.fillMaxSize()) { if (maxWidth \u0026lt; 700.dp) { ListaConteudoCompacta() } else { Row(modifier = Modifier.fillMaxSize()) { ListaConteudoExpandida(modifier = Modifier.weight(1f)) if (mostrarPainelDetalhes) { PainelDetalhes(modifier = Modifier.weight(1f)) } } } } } A grande vantagem do Compose aqui é que o modelo mental continua o mesmo. Você trabalha com estado, composição e layout declarativo, sem precisar reinventar a base a cada plataforma.\nNavegação compartilhada continua sendo peça-chave Uma shared UI só faz sentido de verdade quando a navegação acompanha o resto da arquitetura. Um fluxo simples pode ser definido assim:\nsealed interface Destino { data object Home : Destino data object Configuracoes : Destino data class DetalheProjeto(val id: String) : Destino } class AppNavigator { private val backStack = mutableStateListOf\u0026lt;Destino\u0026gt;(Destino.Home) val destinoAtual: Destino get() = backStack.last() fun navegar(destino: Destino) { backStack += destino } fun voltar() { if (backStack.size \u0026gt; 1) backStack.removeLast() } } Esse padrão é especialmente útil quando você quer manter a regra de navegação no código compartilhado e só delegar o mínimo necessário para cada target.\nSe você trabalha com arquitetura mais modular, isso conversa bem com conceitos de estado e fluxo reativo já vistos no nosso guia completo de coroutines e no artigo sobre Flow em Kotlin.\nCompose Multiplatform substitui nativo em todo caso? Ainda não. E provavelmente essa nem é a pergunta certa.\nA melhor pergunta costuma ser: quanto da minha interface realmente se beneficia de ser compartilhada?\nHoje, Compose Multiplatform tende a fazer mais sentido em cenários como:\naplicativos de produto interno; dashboards e ferramentas corporativas; apps com regra de negócio forte e interface relativamente padronizada; times que já usam Kotlin tanto no Android quanto em módulos compartilhados; apps desktop e mobile que se beneficiam de um mesmo design system. Já em produtos com experiência iOS extremamente específica, animações muito customizadas ou dependência forte de APIs nativas de interface, talvez a melhor estratégia continue sendo compartilhar apenas domínio e dados.\nComo atualizar um projeto existente para 1.10.6 Se você já usa Compose Multiplatform, a atualização deve ser tratada como uma mudança controlada. Um checklist prático seria:\natualizar Kotlin e plugin do Compose em branch separada; revisar bibliotecas acopladas a Material 3 e navegação; validar compilação por target; testar assets compartilhados e tema; revisar componentes responsivos em telas grandes. Exemplo de verificação simples:\n./gradlew :composeApp:assemble ./gradlew :composeApp:iosSimulatorArm64Test ./gradlew :composeApp:desktopTest Essa abordagem evita a armadilha de assumir que “compilou em Android, então está tudo certo”. Em shared UI, o valor está justamente em garantir que os targets continuem coerentes.\nComo isso se posiciona frente a Flutter e React Native? A comparação continua inevitável. O Compose Multiplatform entra forte principalmente para equipes que já vivem no ecossistema Kotlin.\nSe o time é Android-first, a curva de adoção costuma ser menor. Se o projeto já usa KMP para lógica compartilhada, compartilhar UI passa a ser um passo natural. Se a empresa quer aproveitar conhecimento prévio de Compose, a produtividade pode subir rápido. Ao mesmo tempo, outras stacks continuam fortes. Para comparação de mentalidade entre ecossistemas, vale observar como times Python costumam separar UI e automação em ferramentas distintas e como o ecossistema Go normalmente prioriza simplicidade operacional acima de camadas visuais compartilhadas. O diferencial do Compose Multiplatform é justamente unir linguagem, UI e arquitetura em uma experiência mais coesa.\nVale a pena apostar no Compose Multiplatform 1.10.6? Para muitos times, sim. A versão 1.10.6 ajuda a consolidar a percepção de que o Compose Multiplatform já pode ser tratado como ferramenta séria dentro de um roadmap moderno. Ele não elimina análise arquitetural, nem substitui nativo em todos os contextos, mas já oferece maturidade suficiente para sair da curiosidade e entrar em prova de valor real.\nSe sua equipe já usa Kotlin, Compose ou KMP, a resposta tende a ser ainda mais favorável. O caminho mais seguro é começar por um fluxo bem delimitado, validar a experiência em duas plataformas e medir custo de manutenção contra o cenário anterior.\nEm 2026, esse talvez seja o ponto mais importante: o Compose Multiplatform não é mais apenas o “futuro promissor” do Kotlin. Em muitos projetos, ele já começou a virar presente.\n","permalink":"https://kotlin.dev.br/blog/compose-multiplatform-1-10-6-2026/","summary":"\u003cp\u003eO \u003cstrong\u003eCompose Multiplatform 1.10.6\u003c/strong\u003e reforça uma percepção que ficou muito mais clara em 2026: compartilhar interface com Kotlin deixou de ser experimento para virar opção concreta em projetos reais. A página de releases do ecossistema AndroidX já mostra uma linha estável consistente para os principais artefatos do Compose, enquanto Material 3 e recursos adaptativos continuam amadurecendo.\u003c/p\u003e\n\u003cp\u003ePara quem acompanha o avanço do Kotlin no mobile e no desktop, essa versão importa porque ela consolida um baseline confiável para times que querem reduzir fragmentação entre plataformas. Em vez de olhar apenas para demos, agora dá para falar sobre \u003cstrong\u003esetup previsível, bibliotecas estáveis, navegação compartilhada, recursos comuns e estratégia de atualização\u003c/strong\u003e.\u003c/p\u003e","title":"Compose Multiplatform 1.10.6: O Que Mudou em 2026 | Kotlin Brasil"},{"content":"O ritmo de releases do Kotlin mudou bastante nos últimos ciclos. Em vez de esperar apenas grandes versões anuais, o ecossistema agora entrega releases de linguagem, tooling e correções com uma cadência mais previsível. Dentro desse modelo, o Kotlin 2.3.20 se destaca como uma atualização prática para times que querem melhorar build, plugin setup e estabilidade sem necessariamente passar por uma mudança grande de linguagem.\nSe você acompanha o ecossistema, já viu que o site oficial passou a diferenciar com clareza as linhas 2.x.0, 2.x.20 e 2.x.yz. Isso ajuda bastante a decidir quando atualizar. Para quem mantém projeto Android, backend com Spring ou Ktor, bibliotecas JVM e módulos compartilhados, a release 2.3.20 entra naquela categoria de upgrade que vale acompanhar cedo.\nNeste artigo, você vai entender o que muda no Kotlin 2.3.20, quando faz sentido atualizar, como fazer o upgrade no Gradle e no Maven, e quais cuidados tomar para validar a migração com segurança.\nO que é uma release 2.x.20 no Kotlin? Antes de falar da 2.3.20 em si, vale entender o novo modelo de versão do Kotlin:\n2.x.0: release de linguagem, com mudanças maiores; 2.x.20: release de tooling, com foco em produtividade, performance e integração; 2.x.yz: patch release, mais voltada para correções pontuais. Na prática, isso significa que a 2.3.20 não tenta reinventar a linguagem. O foco está em melhorar a experiência de desenvolvimento, reduzir atritos na configuração do projeto e refinar o que já chegou nas versões recentes. Para times de produto, isso normalmente é uma ótima notícia: menos risco de mudança sintática e mais ganho operacional.\nSe você ainda está consolidando as novidades do ciclo anterior, também vale ler nosso conteúdo sobre Kotlin 2.1 e suas melhorias em 2026.\nPor que o Kotlin 2.3.20 chama atenção em 2026? De acordo com a documentação oficial e os anúncios recentes da JetBrains, a 2.3.20 entra como uma release importante por três motivos principais:\nmelhorias de performance e tooling; ajustes na experiência de configuração em Gradle e Maven; evolução contínua do ecossistema que já roda com K2 como padrão. Mesmo quando a release note não apresenta um recurso “de palco”, esse tipo de atualização costuma impactar diretamente o dia a dia. Builds mais consistentes, plugins mais alinhados e menos incompatibilidades entre versões significam menos tempo perdido com infraestrutura de projeto.\nPara quem trabalha com builds grandes, isso conversa diretamente com temas que já exploramos no guia de Gradle com Kotlin e no artigo sobre Amper para projetos Kotlin modernos.\nO que muda na prática para projetos reais? A melhor forma de pensar na 2.3.20 é como uma release de manutenção inteligente. Você não precisa reescrever código por causa dela, mas pode ganhar em previsibilidade.\n1. Upgrade mais claro no plugin Kotlin Em muitos projetos, o primeiro contato com uma nova release acontece no plugin do Gradle:\nplugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.3.20\u0026#34; } No caso de Android, algo comum seria:\nplugins { id(\u0026#34;com.android.application\u0026#34;) kotlin(\u0026#34;android\u0026#34;) version \u0026#34;2.3.20\u0026#34; } android { namespace = \u0026#34;br.dev.kotlin.app\u0026#34; compileSdk = 36 defaultConfig { minSdk = 24 targetSdk = 36 } } Esse tipo de mudança parece simples, mas afeta o conjunto inteiro de tasks de compilação, testes, lint e integração com plugins adicionais.\n2. Mais previsibilidade para projetos com múltiplos módulos Projetos Kotlin modernos raramente ficam em um único módulo. É comum ter separação entre app, core, data, domain, shared, backend e até módulos multiplataforma.\nCom uma release de tooling mais madura, fica mais fácil manter consistência entre esses módulos usando catálogo de versões ou convention plugins.\n// build-logic/src/main/kotlin/kotlin-conventions.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) } kotlin { jvmToolchain(21) } tasks.withType\u0026lt;Test\u0026gt;().configureEach { useJUnitPlatform() } Depois, nos módulos:\nplugins { id(\u0026#34;kotlin-conventions\u0026#34;) } dependencies { implementation(kotlin(\u0026#34;stdlib\u0026#34;)) testImplementation(kotlin(\u0026#34;test\u0026#34;)) } Quando o ecossistema melhora tooling, esse tipo de padronização tende a funcionar com menos surpresa.\n3. Integração melhor com bibliotecas do ecossistema Toda atualização de Kotlin precisa ser vista em conjunto com bibliotecas como:\nkotlinx-coroutines kotlinx-serialization plugins de análise estática frameworks como Spring Boot e Ktor plugins do Compose Por isso, atualizar Kotlin não é só trocar uma string de versão. O ideal é validar se as peças ao redor acompanham o mesmo ritmo. Isso já ficou evidente no patch 2.3.10, que chamou atenção por corrigir uma condição de corrida rara em kotlinx.serialization.\nSe você trabalha com serialização, filas, I/O concorrente ou APIs backend, faz sentido aproveitar a atualização para revisar dependências relacionadas.\nComo atualizar para Kotlin 2.3.20 no Gradle A forma mais comum de upgrade hoje passa pelo build.gradle.kts ou pelo libs.versions.toml.\nExemplo com version catalog # gradle/libs.versions.toml [versions] kotlin = \u0026#34;2.3.20\u0026#34; [plugins] kotlin-jvm = { id = \u0026#34;org.jetbrains.kotlin.jvm\u0026#34;, version.ref = \u0026#34;kotlin\u0026#34; } kotlin-android = { id = \u0026#34;org.jetbrains.kotlin.android\u0026#34;, version.ref = \u0026#34;kotlin\u0026#34; } E no módulo:\nplugins { alias(libs.plugins.kotlin.jvm) } Exemplo com plugin direto plugins { id(\u0026#34;org.jetbrains.kotlin.plugin.serialization\u0026#34;) version \u0026#34;2.3.20\u0026#34; kotlin(\u0026#34;plugin.spring\u0026#34;) version \u0026#34;2.3.20\u0026#34; } Esse padrão ajuda bastante em times que usam backend com Spring, microsserviços ou aplicações com serialização intensiva.\nExemplo de validação depois do upgrade Depois de atualizar a versão, é importante garantir que o projeto continua compilando e executando os testes principais.\nclass CalculadoraPrecoService { fun total(subtotal: Double, desconto: Double): Double { require(subtotal \u0026gt;= 0) { \u0026#34;Subtotal inválido\u0026#34; } require(desconto \u0026gt;= 0) { \u0026#34;Desconto inválido\u0026#34; } return (subtotal - desconto).coerceAtLeast(0.0) } } class CalculadoraPrecoServiceTest { @Test fun `deve calcular total com desconto`() { val service = CalculadoraPrecoService() val resultado = service.total( subtotal = 250.0, desconto = 30.0, ) assertEquals(220.0, resultado) } } Esse snippet é simples de propósito. O ponto é: após um upgrade de tooling, comece validando o essencial:\ncompilação local; testes unitários; integração com plugins críticos; geração de artefatos; pipeline de CI. Se você mantém automação de deploy, também vale revisar nosso conteúdo sobre GitHub Actions com Kotlin e CI/CD no ecossistema Kotlin.\nE no Maven, como fica? Embora o Gradle domine o ecossistema Kotlin, muitos projetos corporativos ainda usam Maven. A atualização é direta:\n\u0026lt;properties\u0026gt; \u0026lt;kotlin.version\u0026gt;2.3.20\u0026lt;/kotlin.version\u0026gt; \u0026lt;/properties\u0026gt; Ou diretamente no plugin:\n\u0026lt;plugin\u0026gt; \u0026lt;groupId\u0026gt;org.jetbrains.kotlin\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;kotlin-maven-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.3.20\u0026lt;/version\u0026gt; \u0026lt;/plugin\u0026gt; Para equipes em ambiente enterprise, esse detalhe importa bastante. Em muitos casos, o valor da release está menos na novidade sintática e mais em permitir uma base mais estável para continuar evoluindo o produto.\nQuando vale atualizar imediatamente? Nem todo projeto precisa correr para a nova versão no mesmo dia. Mas a atualização costuma valer mais a pena quando você está em um destes cenários:\nProjeto novo ou em reorganização Se o projeto ainda está estruturando build, módulos e plugins, começar com a versão recente reduz retrabalho futuro.\nTime que já usa K2 sem problemas Se a base já passou bem pela transição do compilador moderno, atualizar para uma nova release de tooling tende a ser mais tranquilo.\nNecessidade de alinhar dependências do ecossistema Bibliotecas e plugins acompanham o ritmo do Kotlin. Ficar muito atrás pode gerar incompatibilidades desnecessárias.\nPipeline sensível a tempo de build Qualquer melhoria incremental de performance em compilação ou tooling pode virar ganho real em squads com CI pesado.\nQuando é melhor esperar um pouco? Também existem situações em que vale fazer rollout com mais calma:\nprojeto Android com muitos plugins legados; stack corporativa muito travada em versões homologadas; monorepo com várias linguagens e integrações sensíveis; dependência forte de plugins ainda não validados na nova release. Nesses casos, o ideal é criar uma branch de teste, atualizar o Kotlin e medir:\n./gradlew clean test assemble Se tudo passar, você já ganha segurança para seguir com rollout progressivo.\nKotlin 2.3.20 muda código de aplicação? Na maioria dos casos, não. Esse é justamente um dos pontos positivos da release. Você provavelmente não vai precisar alterar funções, classes ou APIs só para compilar. O valor está em melhorar a camada de build e ferramentas que sustenta o projeto.\nIsso faz da 2.3.20 uma release interessante para times pragmáticos. Não é uma atualização para “parecer moderno”; é uma atualização para manter o ecossistema saudável, alinhado e com menos atrito operacional.\nVale a pena adotar o Kotlin 2.3.20? De forma geral, sim — especialmente se seu projeto já está em uma linha recente do Kotlin. A 2.3.20 parece ser o tipo de release que refina a experiência de desenvolvimento, melhora o setup e prepara o terreno para o que vem na 2.4.0.\nA recomendação prática é simples:\natualize em branch separada; revise plugins e bibliotecas do ecossistema; rode testes e build completo; acompanhe o comportamento do CI antes de promover para toda a equipe. Para quem vive Kotlin no dia a dia, esse tipo de manutenção contínua costuma custar pouco e render bastante. E, num ecossistema que está acelerando Android, backend, multiplataforma e web ao mesmo tempo, manter a base técnica em dia deixou de ser detalhe — virou vantagem competitiva. Para comparar como outras linguagens gerenciam releases incrementais, veja como Go mantém compatibilidade rigorosa entre versões e como Rust usa o sistema de editions para evoluir sem quebrar código existente.\n","permalink":"https://kotlin.dev.br/blog/kotlin-2-3-20-novidades/","summary":"\u003cp\u003eO ritmo de releases do Kotlin mudou bastante nos últimos ciclos. Em vez de esperar apenas grandes versões anuais, o ecossistema agora entrega \u003cstrong\u003ereleases de linguagem, tooling e correções\u003c/strong\u003e com uma cadência mais previsível. Dentro desse modelo, o \u003cstrong\u003eKotlin 2.3.20\u003c/strong\u003e se destaca como uma atualização prática para times que querem melhorar build, plugin setup e estabilidade sem necessariamente passar por uma mudança grande de linguagem.\u003c/p\u003e\n\u003cp\u003eSe você acompanha o ecossistema, já viu que o site oficial passou a diferenciar com clareza as linhas \u003ccode\u003e2.x.0\u003c/code\u003e, \u003ccode\u003e2.x.20\u003c/code\u003e e \u003ccode\u003e2.x.yz\u003c/code\u003e. Isso ajuda bastante a decidir quando atualizar. Para quem mantém projeto Android, backend com Spring ou Ktor, bibliotecas JVM e módulos compartilhados, a release 2.3.20 entra naquela categoria de upgrade que vale acompanhar cedo.\u003c/p\u003e","title":"Kotlin 2.3.20: Novidades Práticas da Release | Kotlin Brasil"},{"content":"Durante muitos anos, a conversão de Java para Kotlin ficou fortemente associada ao IntelliJ IDEA. Faz sentido: a JetBrains sempre ofereceu uma experiência excelente de migração dentro da própria IDE. Mas em 2026 surgiu uma novidade importante para o ecossistema: a possibilidade de converter Java para Kotlin no Visual Studio Code.\nPara quem trabalha em equipes heterogêneas, usa VS Code no dia a dia ou quer experimentar Kotlin sem trocar imediatamente de editor, isso reduz uma barreira importante de adoção. Neste artigo, vamos entender o que muda na prática, quando esse fluxo ajuda de verdade e quais cuidados você precisa ter para migrar código Java com qualidade.\nPor que essa novidade importa? A migração de Java para Kotlin quase nunca é apenas um detalhe técnico. Ela costuma estar ligada a objetivos maiores, como:\nreduzir boilerplate; melhorar null safety; aumentar legibilidade; adotar coroutines e APIs mais modernas; facilitar a evolução de aplicações Android e backend. Ao levar uma etapa importante dessa jornada para o VS Code, o ecossistema Kotlin fica mais acessível. Isso é relevante principalmente para pessoas que já vivem em ambientes mistos, usam múltiplas linguagens no mesmo monorepo ou preferem editores mais leves.\nSe você ainda está avaliando a migração como estratégia, vale ler também nosso artigo sobre Kotlin vs Java em 2026 e o guia para desenvolvedores Java.\nO que a conversão faz na prática? A proposta da ferramenta é acelerar o primeiro passo da migração. Em vez de reescrever classes manualmente, você parte de um arquivo Java e gera uma versão inicial em Kotlin para depois refinar.\nConsidere esta classe Java:\nimport java.math.BigDecimal; import java.util.Objects; public class PedidoService { public BigDecimal calcularTotal(BigDecimal subtotal, BigDecimal frete) { Objects.requireNonNull(subtotal, \u0026#34;subtotal é obrigatório\u0026#34;); Objects.requireNonNull(frete, \u0026#34;frete é obrigatório\u0026#34;); return subtotal.add(frete); } public boolean isFreteGratis(BigDecimal subtotal) { return subtotal.compareTo(new BigDecimal(\u0026#34;199.90\u0026#34;)) \u0026gt;= 0; } } Uma conversão inicial para Kotlin pode ficar assim:\nimport java.math.BigDecimal class PedidoService { fun calcularTotal(subtotal: BigDecimal, frete: BigDecimal): BigDecimal { return subtotal.add(frete) } fun isFreteGratis(subtotal: BigDecimal): Boolean { return subtotal \u0026gt;= BigDecimal(\u0026#34;199.90\u0026#34;) } } A principal vantagem é ganhar velocidade. A principal limitação é que o código convertido quase nunca é o código final ideal. Ele precisa de revisão humana.\nConversão não é refatoração completa Esse é o ponto mais importante do artigo. Converter Java para Kotlin não significa automaticamente escrever Kotlin idiomático.\nUma classe convertida pode continuar com:\nnomes herdados de um estilo Java antigo; uso excessivo de classes utilitárias; APIs mutáveis demais; excesso de BigDecimal, Optional, builders ou getters/setters sem necessidade; ausência de recursos idiomáticos como data classes, extension functions e sealed classes. Veja um exemplo.\nCódigo Java original public class UsuarioDto { private final String nome; private final String email; public UsuarioDto(String nome, String email) { this.nome = nome; this.email = email; } public String getNome() { return nome; } public String getEmail() { return email; } } Conversão automática plausível class UsuarioDto( private val nome: String, private val email: String, ) { fun getNome(): String = nome fun getEmail(): String = email } Refatoração idiomática em Kotlin data class UsuarioDto( val nome: String, val email: String, ) A ferramenta ajuda a sair do zero, mas o ganho real vem da refatoração posterior.\nFluxo recomendado para migrar com segurança Uma boa estratégia é tratar a conversão como uma etapa intermediária.\n1. Converter arquivos pequenos primeiro Comece por classes utilitárias, DTOs, serviços simples ou módulos de baixo acoplamento. Isso reduz risco e facilita aprendizado do time.\n2. Rodar testes imediatamente Toda migração precisa estar protegida por testes de regressão. Se ainda faltam testes, vale parar e criar cobertura antes de converter partes críticas.\nimport org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import java.math.BigDecimal class PedidoServiceTest { private val service = PedidoService() @Test fun `deve somar subtotal e frete`() { val total = service.calcularTotal( subtotal = BigDecimal(\u0026#34;150.00\u0026#34;), frete = BigDecimal(\u0026#34;19.90\u0026#34;), ) assertEquals(BigDecimal(\u0026#34;169.90\u0026#34;), total) } } Se você precisar reforçar a base de testes antes da migração, veja nosso guia de testes com JUnit 5 e MockK.\n3. Refatorar para Kotlin idiomático Depois de converter, revise:\nnulabilidade; mutabilidade desnecessária; data classes; coleções; uso de when; extensões; redução de boilerplate. 4. Migrar por fronteiras de módulo Em sistemas maiores, normalmente funciona melhor migrar por pacote, módulo ou domínio do que converter arquivos soltos sem estratégia.\nExemplo real de melhoria após conversão Imagine uma classe Java de validação:\nimport java.util.ArrayList; import java.util.List; public class CadastroValidator { public List\u0026lt;String\u0026gt; validar(String nome, String email, int idade) { List\u0026lt;String\u0026gt; erros = new ArrayList\u0026lt;\u0026gt;(); if (nome == null || nome.trim().isEmpty()) { erros.add(\u0026#34;Nome obrigatório\u0026#34;); } if (email == null || !email.contains(\u0026#34;@\u0026#34;)) { erros.add(\u0026#34;Email inválido\u0026#34;); } if (idade \u0026lt; 18) { erros.add(\u0026#34;Idade mínima de 18 anos\u0026#34;); } return erros; } } Uma versão Kotlin mais idiomática pode ficar assim:\nclass CadastroValidator { fun validar(nome: String?, email: String?, idade: Int): List\u0026lt;String\u0026gt; { return buildList { if (nome.isNullOrBlank()) add(\u0026#34;Nome obrigatório\u0026#34;) if (email.isNullOrBlank() || \u0026#34;@\u0026#34; !in email) add(\u0026#34;Email inválido\u0026#34;) if (idade \u0026lt; 18) add(\u0026#34;Idade mínima de 18 anos\u0026#34;) } } } Aqui o ganho não está só na sintaxe menor. Está também em clareza, modelagem de nulabilidade e menor ruído visual.\nOnde o VS Code pode ajudar mais? Essa novidade tende a ser útil principalmente nestes cenários:\nEquipes com adoção gradual de Kotlin Nem todo time vai padronizar IntelliJ de imediato. Com conversão no VS Code, a entrada no ecossistema fica mais suave.\nMonorepos com múltiplas linguagens Times que alternam entre TypeScript, Python, Go, Java e Kotlin costumam valorizar uma ferramenta única de edição. Isso vale especialmente para backend e plataformas internas.\nEstudos e provas de conceito Se a empresa quer validar Kotlin em um módulo pequeno, poder fazer a conversão no editor já usado pela equipe facilita muito.\nLimites que você precisa conhecer Mesmo sendo uma novidade valiosa, a conversão tem limites práticos.\nAPIs Java complexas continuam exigindo atenção Herança profunda, reflection, frameworks legados e anotações muito específicas podem gerar código convertido funcional, mas longe do ideal.\nNullability precisa de revisão manual Uma das maiores forças do Kotlin é o null safety. Mas ele não aparece automaticamente com perfeição em toda migração, principalmente quando o código Java original não expressa contratos de nulidade de forma clara.\nNem todo padrão Java deve sobreviver Migrar para Kotlin mantendo todos os padrões Java antigos pode desperdiçar o benefício da linguagem.\nKotlin idiomático depois da conversão Depois de converter, procure oportunidades para aplicar recursos mais naturais da linguagem:\ndata class para modelos simples; sealed class para estados e resultados; extension functions para utilidades de domínio; when para fluxos de decisão mais claros; coroutines para assincronia moderna. Por exemplo, em vez de retornar null ou lançar exceções genéricas, você pode modelar melhor os resultados:\nsealed interface ResultadoCadastro { data class Sucesso(val id: Long) : ResultadoCadastro data class ErroValidacao(val mensagens: List\u0026lt;String\u0026gt;) : ResultadoCadastro } fun cadastrar(nome: String, email: String): ResultadoCadastro { val erros = CadastroValidator().validar(nome, email, 20) if (erros.isNotEmpty()) { return ResultadoCadastro.ErroValidacao(erros) } return ResultadoCadastro.Sucesso(id = 42L) } Esse tipo de refatoração aproxima o código do que há de melhor no Kotlin atual.\nComparando a experiência com outras linguagens Ferramentas de migração e modernização não são exclusividade do Kotlin. O ecossistema Python também vive ciclos constantes de modernização de código entre versões e estilos de tipagem, enquanto o ecossistema Go costuma privilegiar simplicidade e refatoração gradual em bases de código grandes. No caso do Kotlin, a vantagem é migrar a partir do Java mantendo interoperabilidade direta com a JVM.\nVale a pena usar no dia a dia? Sim, desde que você encare a conversão como acelerador, não como solução mágica. Para times que já usam VS Code, a novidade reduz atrito. Para quem está começando a avaliar Kotlin, ela transforma a migração em algo mais acessível. E para equipes experientes, pode economizar tempo em lotes iniciais de conversão.\nO segredo está em combinar três coisas:\nconversão automática para ganhar velocidade; testes para garantir segurança; refatoração para alcançar qualidade idiomática. Conclusão A conversão de Java para Kotlin no VS Code é uma daquelas melhorias que parecem pequenas à primeira vista, mas têm impacto estratégico. Ela reduz barreiras de entrada, amplia o alcance do ecossistema Kotlin e ajuda equipes a iniciar migrações sem depender de uma única IDE.\nSe o seu contexto é Android, backend ou bibliotecas JVM, essa novidade vale um teste prático. Comece por classes simples, rode os testes, ajuste nulabilidade e refatore para Kotlin idiomático. Assim, você transforma a conversão em uma migração real de qualidade — e não apenas em troca de sintaxe.\nPara seguir nessa jornada, leia também Kotlin vs Java, Kotlin para desenvolvedores Java e o que mudou no Kotlin em 2026.\n","permalink":"https://kotlin.dev.br/blog/kotlin-vscode-converter-java-kotlin-2026/","summary":"\u003cp\u003eDurante muitos anos, a conversão de Java para Kotlin ficou fortemente associada ao IntelliJ IDEA. Faz sentido: a JetBrains sempre ofereceu uma experiência excelente de migração dentro da própria IDE. Mas em 2026 surgiu uma novidade importante para o ecossistema: a possibilidade de \u003cstrong\u003econverter Java para Kotlin no Visual Studio Code\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003ePara quem trabalha em equipes heterogêneas, usa VS Code no dia a dia ou quer experimentar Kotlin sem trocar imediatamente de editor, isso reduz uma barreira importante de adoção. Neste artigo, vamos entender o que muda na prática, quando esse fluxo ajuda de verdade e quais cuidados você precisa ter para migrar código Java com qualidade.\u003c/p\u003e","title":"VS Code Kotlin: Converter Java para Kotlin em 2026 | Kotlin Brasil"},{"content":"O ecossistema Kotlin sempre teve uma relação muito forte com o Gradle. Ele continua sendo a principal ferramenta de build para boa parte dos projetos Android, backend e multiplataforma. Mas em 2026 a JetBrains acelerou um movimento importante: o Amper, uma nova ferramenta de build e automação pensada para oferecer uma experiência mais simples, previsível e amigável para projetos Kotlin modernos.\nSe você já sentiu que configurar build.gradle.kts, plugins, convention plugins, versões de JDK e módulos multiplataforma exige tempo demais, o Amper merece sua atenção. Neste guia, você vai entender o que é o Amper, quando usar, como estruturar um projeto e onde ele faz mais sentido no dia a dia.\nO que é o Amper? O Amper é uma ferramenta da JetBrains voltada para simplificar a configuração e a manutenção de projetos Kotlin e JVM. Em vez de começar por uma DSL extensa como a do Gradle, a proposta do Amper é trabalhar com arquivos declarativos menores, foco em convenções e menos boilerplate.\nNa prática, o Amper tenta resolver dores comuns como:\nconfiguração inicial demorada; excesso de detalhes para tarefas simples; diferença grande entre projetos pequenos e setups corporativos; complexidade para onboarding de pessoas novas no repositório. Isso não significa “substituir o Gradle em todos os cenários” imediatamente. A ideia atual é oferecer uma camada mais direta para casos em que times querem produtividade, menos configuração manual e um caminho mais guiado pela JetBrains.\nPor que o Amper ganhou relevância em 2026? A evolução recente do Amper trouxe recursos que o tornam mais viável para uso real em projetos de equipe. Entre os destaques mais comentados pela comunidade estão:\nprovisionamento de JDK mais simples; melhor organização por módulos; integração com plugins de compilador; conversão de projetos Maven; experiência mais consistente para Kotlin Multiplatform. Esse movimento acompanha a maturidade do ecossistema Kotlin. Hoje já temos um compilador mais moderno com o K2 como padrão, mais projetos usando Kotlin Multiplatform e uma busca maior por pipelines reproduzíveis em times que também trabalham com CI/CD em Kotlin.\nComo o Amper se diferencia do Gradle? O Gradle é extremamente poderoso. O problema é que esse poder normalmente vem com mais camadas de configuração, mais DSL e mais decisões arquiteturais logo no começo do projeto. O Amper tenta reduzir esse custo cognitivo.\nComparação prática Aspecto Gradle Amper Flexibilidade Muito alta Alta, mas mais guiada Complexidade inicial Média para alta Baixa para média Boilerplate Maior Menor Curva de aprendizado Mais longa Mais curta Convenções prontas Menos opinativo Mais opinativo Se você trabalha com automação e build tooling, vale lembrar que essa busca por configuração mais previsível também aparece em outras linguagens. O ecossistema Go costuma priorizar ferramentas com convenções simples e pouca configuração, enquanto o ecossistema Python muitas vezes combina ferramentas menores para empacotamento, lint e automação.\nEstrutura básica de um projeto com Amper Um projeto com Amper tende a ser mais declarativo. Em vez de concentrar tudo em um build.gradle.kts enorme, você descreve módulos, dependências e targets de forma mais enxuta.\nUm exemplo conceitual de estrutura pode ficar assim:\nmeu-projeto/ ├── amper.yaml ├── app/ │ ├── src/commonMain/kotlin/ │ ├── src/jvmMain/kotlin/ │ └── module.yaml ├── backend/ │ ├── src/main/kotlin/ │ └── module.yaml └── shared/ ├── src/commonMain/kotlin/ └── module.yaml A proposta é que cada módulo exponha apenas o necessário, com uma definição mais legível para quem acabou de entrar no time.\nExemplo de configuração declarativa A sintaxe do Amper pode evoluir com o tempo, mas a ideia geral é declarar módulo, plataforma e dependências sem a verbosidade comum de builds muito customizados.\nproduct: type: app platforms: [jvm] modules: - ./shared - ./backend dependencies: - org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 - io.ktor:ktor-server-core:3.0.0 - io.ktor:ktor-server-netty:3.0.0 test-dependencies: - org.jetbrains.kotlin:kotlin-test - org.junit.jupiter:junit-jupiter:5.10.2 Mesmo que o formato exato varie por versão, a diferença de filosofia fica clara: você descreve o projeto em termos de intenção, e não de orquestração detalhada de tasks.\nCriando um módulo compartilhado Um dos cenários mais interessantes para o Amper é o de projetos com código compartilhado. Isso aparece muito em setups multiplataforma, SDKs internos e bibliotecas reutilizáveis.\nproduct: type: library platforms: [jvm, ios, android] dependencies: - org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0 - org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 E no código Kotlin:\nimport kotlinx.datetime.Clock import kotlinx.serialization.Serializable @Serializable data class BuildInfo( val nomeProjeto: String, val versao: String, val geradoEm: String, ) fun gerarBuildInfo(nomeProjeto: String, versao: String): BuildInfo { return BuildInfo( nomeProjeto = nomeProjeto, versao = versao, geradoEm = Clock.System.now().toString(), ) } Esse tipo de módulo pode ser consumido por uma aplicação Android, um backend ou um utilitário interno sem repetir lógica de serialização e metadados.\nTestes com Amper Projetos modernos precisam de testes como parte do fluxo desde o primeiro commit. O Amper ajuda ao deixar a configuração mais previsível, sem impedir o uso das bibliotecas tradicionais do ecossistema Kotlin.\ntest-dependencies: - org.jetbrains.kotlin:kotlin-test - io.mockk:mockk:1.13.10 - org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.0 Com isso, você consegue manter um setup de testes familiar:\nimport io.mockk.every import io.mockk.mockk import kotlin.test.Test import kotlin.test.assertEquals class SaudacaoService(private val relogio: Relogio) { fun mensagem(): String { return if (relogio.horaAtual() \u0026lt; 12) \u0026#34;Bom dia\u0026#34; else \u0026#34;Boa tarde\u0026#34; } } interface Relogio { fun horaAtual(): Int } class SaudacaoServiceTest { private val relogio = mockk\u0026lt;Relogio\u0026gt;() private val service = SaudacaoService(relogio) @Test fun `deve retornar bom dia antes do meio-dia`() { every { relogio.horaAtual() } returns 9 assertEquals(\u0026#34;Bom dia\u0026#34;, service.mensagem()) } } Se você quiser aprofundar essa parte, depois vale ler nosso guia de testes em Kotlin com JUnit 5 e MockK.\nOnde o Amper faz mais sentido? Hoje o Amper tende a ser especialmente interessante em alguns contextos:\n1. Projetos novos Quando você ainda não acumulou dezenas de plugins, scripts e integrações históricas, fica mais fácil aproveitar uma abordagem mais limpa.\n2. Times que querem onboarding rápido Menos DSL e menos arquivos espalhados normalmente significam menos tempo até alguém conseguir rodar o projeto localmente.\n3. Projetos multiplataforma Quanto mais targets você adiciona, maior costuma ser a dor de build. Uma ferramenta mais opinativa pode reduzir inconsistências.\n4. Bibliotecas internas e ferramentas de equipe Nem todo projeto precisa da flexibilidade total do Gradle. Ferramentas internas se beneficiam muito de convenção.\nQuando talvez o Gradle ainda seja melhor? O Gradle continua sendo a melhor escolha em vários cenários, especialmente quando você precisa de:\nintegrações muito específicas com plugins corporativos; tasks customizadas complexas; pipelines fortemente acoplados ao ecossistema Gradle; compatibilidade com builds já estabilizados em produção. Ou seja: o Amper não elimina o Gradle. Ele oferece uma opção interessante para reduzir complexidade em casos onde o Gradle pode ser mais ferramenta do que o projeto realmente precisa.\nIntegração com CI Se o seu time adota integração contínua, a principal vantagem do Amper é a previsibilidade do ambiente. Menos configuração manual tende a significar menos divergência entre máquina local e runner.\nUm pipeline conceitual pode seguir este formato:\nsteps: - checkout - setup-jdk - amper build - amper test A ideia é simples: baixar o código, garantir a JDK correta, compilar e rodar testes. Em ambientes que já usam GitHub Actions, Gitea Actions ou outro sistema de CI, isso pode reduzir o número de detalhes específicos do build script.\nAmper e Kotlin Multiplatform O Amper chama atenção principalmente quando combinado com KMP. Em projetos multiplataforma, a configuração de source sets, targets e dependências costuma crescer rápido. Uma ferramenta declarativa ajuda a enxergar melhor a estrutura do projeto.\nIsso é especialmente relevante para quem acompanha a evolução de interfaces compartilhadas com Compose Multiplatform e targets web com Kotlin/Wasm.\nVale a pena aprender Amper agora? Para quem trabalha profissionalmente com Kotlin, a resposta mais equilibrada é: sim, vale acompanhar de perto. Mesmo que seu time continue no Gradle pelos próximos meses, entender o Amper ajuda a:\nacompanhar a direção da JetBrains; avaliar novos projetos com menos boilerplate; testar abordagens mais simples para módulos internos; participar cedo de uma mudança potencialmente importante no ecossistema. Aprender Amper agora não significa migrar tudo. Significa adquirir contexto para decidir melhor quando ele amadurecer ainda mais.\nConclusão O Amper representa uma tentativa séria de simplificar o build no ecossistema Kotlin sem abrir mão da experiência moderna de desenvolvimento. Ele conversa bem com um momento em que o Kotlin está mais amplo, com backend, Android, multiplataforma e ferramentas de produtividade evoluindo ao mesmo tempo.\nSe você quer reduzir atrito de configuração, facilitar onboarding e experimentar uma abordagem mais declarativa, o Amper já merece um projeto piloto. E se o seu foco ainda é Gradle, conhecer essa ferramenta agora ajuda a entender para onde a JetBrains está empurrando a experiência de build.\nPara continuar explorando o ecossistema, leia também nosso conteúdo sobre Kotlin e DevOps, Kotlin com GitHub Actions e o guia de Kotlin para backend.\n","permalink":"https://kotlin.dev.br/blog/amper-kotlin-guia-2026/","summary":"\u003cp\u003eO ecossistema Kotlin sempre teve uma relação muito forte com o Gradle. Ele continua sendo a principal ferramenta de build para boa parte dos projetos Android, backend e multiplataforma. Mas em 2026 a JetBrains acelerou um movimento importante: o \u003cstrong\u003eAmper\u003c/strong\u003e, uma nova ferramenta de build e automação pensada para oferecer uma experiência mais simples, previsível e amigável para projetos Kotlin modernos.\u003c/p\u003e\n\u003cp\u003eSe você já sentiu que configurar \u003ccode\u003ebuild.gradle.kts\u003c/code\u003e, plugins, convention plugins, versões de JDK e módulos multiplataforma exige tempo demais, o Amper merece sua atenção. Neste guia, você vai entender o que é o Amper, quando usar, como estruturar um projeto e onde ele faz mais sentido no dia a dia.\u003c/p\u003e","title":"Amper Kotlin: Como Funciona o Novo Build Tool | Kotlin Brasil"},{"content":"Sobre a vagaA TEAM International busca uma pessoa Desenvolvedora Kotlin Pleno para atuação remota, com elegibilidade para profissionais na Colômbia ou Argentina.\nStack informadaKotlin e JavaTypeScript e ReactKubernetes e AWSSQL, MongoDB e DynamoDBFerramentas Atlassian, incluindo Jira Cloud, Tempo Timesheets, Capacity Planner e Financial ManagerObservaçãoA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos ou benefícios.\n","permalink":"https://kotlin.dev.br/vagas/r7vaavtf9vt6d3wj-team-international-desenvolvedor-kotlin-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA TEAM International busca uma pessoa Desenvolvedora Kotlin Pleno para atuação remota, com elegibilidade para profissionais na Colômbia ou Argentina.\u003c/p\u003e\u003ch3\u003eStack informada\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Java\u003c/li\u003e\u003cli\u003eTypeScript e React\u003c/li\u003e\u003cli\u003eKubernetes e AWS\u003c/li\u003e\u003cli\u003eSQL, MongoDB e DynamoDB\u003c/li\u003e\u003cli\u003eFerramentas Atlassian, incluindo Jira Cloud, Tempo Timesheets, Capacity Planner e Financial Manager\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eObservação\u003c/h3\u003e\u003cp\u003eA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos ou benefícios.\u003c/p\u003e","title":"Desenvolvedor Kotlin Pleno"},{"content":"Sobre a vagaA SAP busca uma pessoa Desenvolvedora Backend Sênior para atuar no SAP Concur em modelo híbrido em São Leopoldo, Rio Grande do Sul.\nTecnologiasKotlin, Java e Go para desenvolvimento backend.AWS, incluindo EC2, DynamoDB, EKS, AMIs e arquiteturas serverless.Docker, Kubernetes e Helm para conteinerização e orquestração.CloudFormation e Terraform para infraestrutura como código.Práticas de CI/CD para entrega contínua.RequisitosExperiência sênior em desenvolvimento backend.Vivência com serviços cloud e ambientes distribuídos.Conhecimento em automação de infraestrutura, containers e pipelines de entrega. ","permalink":"https://kotlin.dev.br/vagas/bz68w04xjdp09cf4-sap-desenvolvedor-backend-senior-sap-concur/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA SAP busca uma pessoa Desenvolvedora Backend Sênior para atuar no SAP Concur em modelo híbrido em São Leopoldo, Rio Grande do Sul.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java e Go para desenvolvimento backend.\u003c/li\u003e\u003cli\u003eAWS, incluindo EC2, DynamoDB, EKS, AMIs e arquiteturas serverless.\u003c/li\u003e\u003cli\u003eDocker, Kubernetes e Helm para conteinerização e orquestração.\u003c/li\u003e\u003cli\u003eCloudFormation e Terraform para infraestrutura como código.\u003c/li\u003e\u003cli\u003ePráticas de CI/CD para entrega contínua.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento backend.\u003c/li\u003e\u003cli\u003eVivência com serviços cloud e ambientes distribuídos.\u003c/li\u003e\u003cli\u003eConhecimento em automação de infraestrutura, containers e pipelines de entrega.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Backend Sênior - SAP Concur"},{"content":"Sobre a vagaA SAP busca um(a) Arquiteto(a) de Software Especialista para atuar no SAP Concur Travel em São Leopoldo, Rio Grande do Sul. A posição é presencial e de nível sênior.\nStack e tecnologiasKotlin, Java, Go e Node.jsDocker, Helm e KubernetesAWS, incluindo EC2, AMI, EKS e DynamoDBResponsabilidadesAtuar na arquitetura de software de soluções ligadas ao SAP Concur Travel.Contribuir com decisões técnicas em sistemas distribuídos e ambientes em nuvem.Colaborar com times de engenharia na definição de padrões, qualidade e evolução da plataforma.RequisitosExperiência sênior em arquitetura e desenvolvimento de software.Vivência com linguagens JVM e desenvolvimento backend.Conhecimento prático em containers, Kubernetes e serviços AWS. ","permalink":"https://kotlin.dev.br/vagas/dyzt59t6y1d8dfvc-sap-arquiteto-a-de-software-especialista-sap-concur-travel/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA SAP busca um(a) Arquiteto(a) de Software Especialista para atuar no SAP Concur Travel em São Leopoldo, Rio Grande do Sul. A posição é presencial e de nível sênior.\u003c/p\u003e\u003ch3\u003eStack e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java, Go e Node.js\u003c/li\u003e\u003cli\u003eDocker, Helm e Kubernetes\u003c/li\u003e\u003cli\u003eAWS, incluindo EC2, AMI, EKS e DynamoDB\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAtuar na arquitetura de software de soluções ligadas ao SAP Concur Travel.\u003c/li\u003e\u003cli\u003eContribuir com decisões técnicas em sistemas distribuídos e ambientes em nuvem.\u003c/li\u003e\u003cli\u003eColaborar com times de engenharia na definição de padrões, qualidade e evolução da plataforma.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em arquitetura e desenvolvimento de software.\u003c/li\u003e\u003cli\u003eVivência com linguagens JVM e desenvolvimento backend.\u003c/li\u003e\u003cli\u003eConhecimento prático em containers, Kubernetes e serviços AWS.\u003c/li\u003e\u003c/ul\u003e","title":"Arquiteto(a) de Software Especialista - SAP Concur Travel"},{"content":"Sobre a vagaA SAP busca uma pessoa Desenvolvedora Backend Sênior para atuar no produto SAP Concur Travel, em modelo presencial em São Leopoldo, Rio Grande do Sul.\nTecnologias mencionadasDocker, Kubernetes e HelmAWS, incluindo EC2 e EKSDynamoDBOpenAI e AnthropicRequisitosExperiência sênior em desenvolvimento Backend.Vivência com arquitetura, operação e entrega de serviços em nuvem.Conhecimento prático em containers, orquestração e infraestrutura na AWS.Local de trabalhoVaga presencial em São Leopoldo, Rio Grande do Sul, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/ep5qhr8kupgb8wye-sap-desenvolvedor-backend-senior-sap-concur-travel/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA SAP busca uma pessoa Desenvolvedora Backend Sênior para atuar no produto SAP Concur Travel, em modelo presencial em São Leopoldo, Rio Grande do Sul.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDocker, Kubernetes e Helm\u003c/li\u003e\u003cli\u003eAWS, incluindo EC2 e EKS\u003c/li\u003e\u003cli\u003eDynamoDB\u003c/li\u003e\u003cli\u003eOpenAI e Anthropic\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento Backend.\u003c/li\u003e\u003cli\u003eVivência com arquitetura, operação e entrega de serviços em nuvem.\u003c/li\u003e\u003cli\u003eConhecimento prático em containers, orquestração e infraestrutura na AWS.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em São Leopoldo, Rio Grande do Sul, Brasil.\u003c/p\u003e","title":"Desenvolvedor Backend Sênior - SAP Concur Travel"},{"content":"Sobre a vagaO iFood busca uma pessoa Backend Software Engineer Sênior para atuação remota no Brasil.\nEsta é uma vaga afirmativa para pessoas negras.\nTecnologiasKotlin, Java e RustAWS, Linux, Kubernetes e DockerKafka, SQS, SNS e RabbitMQPerfilNível sênior em engenharia de software backend.Experiência com sistemas distribuídos e mensageria.Vivência com infraestrutura em nuvem e ambientes conteinerizados. ","permalink":"https://kotlin.dev.br/vagas/qvm9gs4ky3gt040n-ifood-backend-software-engineer-senior-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO iFood busca uma pessoa \u003cstrong\u003eBackend Software Engineer Sênior\u003c/strong\u003e para atuação remota no Brasil.\u003c/p\u003e\u003cp\u003eEsta é uma \u003cstrong\u003evaga afirmativa para pessoas negras\u003c/strong\u003e.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java e Rust\u003c/li\u003e\u003cli\u003eAWS, Linux, Kubernetes e Docker\u003c/li\u003e\u003cli\u003eKafka, SQS, SNS e RabbitMQ\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cul\u003e\u003cli\u003eNível sênior em engenharia de software backend.\u003c/li\u003e\u003cli\u003eExperiência com sistemas distribuídos e mensageria.\u003c/li\u003e\u003cli\u003eVivência com infraestrutura em nuvem e ambientes conteinerizados.\u003c/li\u003e\u003c/ul\u003e","title":"Backend Software Engineer Sênior Kotlin"},{"content":"Quando se fala em acesso a banco de dados no ecossistema Kotlin, o Hibernate costuma ser a primeira opção por causa da integração com Spring Boot. Mas existe uma alternativa 100% Kotlin, criada pela própria JetBrains: o Exposed. Neste tutorial, vamos explorar como ele funciona, suas duas abordagens (DSL e DAO), e por que ele pode ser a melhor escolha para o seu próximo projeto. Para uma visão mais aplicada com PostgreSQL, pool de conexões e migrations, leia também Kotlin com PostgreSQL no backend.\nO que é o Exposed? O Exposed é um framework SQL leve para Kotlin, mantido pela JetBrains. Ele oferece duas formas de trabalhar com bancos de dados:\nDSL (Domain Specific Language): escrita de queries com sintaxe type-safe, parecida com SQL DAO (Data Access Object): mapeamento objeto-relacional no estilo ORM tradicional A grande vantagem? Tudo é escrito em Kotlin puro, com inferência de tipos, null safety e suporte nativo a coroutines.\nConfiguração do projeto Adicione as dependências no build.gradle.kts:\ndependencies { // Exposed core implementation(\u0026#34;org.jetbrains.exposed:exposed-core:0.56.0\u0026#34;) implementation(\u0026#34;org.jetbrains.exposed:exposed-dao:0.56.0\u0026#34;) implementation(\u0026#34;org.jetbrains.exposed:exposed-jdbc:0.56.0\u0026#34;) implementation(\u0026#34;org.jetbrains.exposed:exposed-java-time:0.56.0\u0026#34;) // Driver do banco (exemplo com PostgreSQL) implementation(\u0026#34;org.postgresql:postgresql:42.7.4\u0026#34;) // Connection pool implementation(\u0026#34;com.zaxxer:HikariCP:6.2.1\u0026#34;) } Definindo tabelas com DSL No Exposed, tabelas são objetos Kotlin que herdam de Table:\nimport org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.javatime.datetime object Usuarios : Table(\u0026#34;usuarios\u0026#34;) { val id = integer(\u0026#34;id\u0026#34;).autoIncrement() val nome = varchar(\u0026#34;nome\u0026#34;, 100) val email = varchar(\u0026#34;email\u0026#34;, 255).uniqueIndex() val ativo = bool(\u0026#34;ativo\u0026#34;).default(true) val criadoEm = datetime(\u0026#34;criado_em\u0026#34;) override val primaryKey = PrimaryKey(id) } object Pedidos : Table(\u0026#34;pedidos\u0026#34;) { val id = integer(\u0026#34;id\u0026#34;).autoIncrement() val usuarioId = integer(\u0026#34;usuario_id\u0026#34;).references(Usuarios.id) val total = decimal(\u0026#34;total\u0026#34;, 10, 2) val status = varchar(\u0026#34;status\u0026#34;, 50) val criadoEm = datetime(\u0026#34;criado_em\u0026#34;) override val primaryKey = PrimaryKey(id) } Note como as colunas são type-safe — o compilador garante que você não vai comparar um integer com um varchar por engano. Isso é algo que frameworks ORM em linguagens como Go também buscam alcançar, mas o sistema de tipos do Kotlin torna a experiência muito mais fluida.\nConectando ao banco import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.transactions.transaction fun inicializarBanco() { val config = HikariConfig().apply { jdbcUrl = \u0026#34;jdbc:postgresql://localhost:5432/meu_app\u0026#34; driverClassName = \u0026#34;org.postgresql.Driver\u0026#34; username = \u0026#34;postgres\u0026#34; password = \u0026#34;senha_segura\u0026#34; maximumPoolSize = 10 } Database.connect(HikariDataSource(config)) // Criar tabelas automaticamente transaction { SchemaUtils.create(Usuarios, Pedidos) } } Operações CRUD com DSL Create — Inserindo registros import org.jetbrains.exposed.sql.insert import org.jetbrains.exposed.sql.transactions.transaction import java.time.LocalDateTime transaction { Usuarios.insert { it[nome] = \u0026#34;João Silva\u0026#34; it[email] = \u0026#34;joao@email.com\u0026#34; it[ativo] = true it[criadoEm] = LocalDateTime.now() } } Para inserir e obter o ID gerado:\nval novoId = transaction { Usuarios.insertAndGetId { it[nome] = \u0026#34;Maria Santos\u0026#34; it[email] = \u0026#34;maria@email.com\u0026#34; it[criadoEm] = LocalDateTime.now() } } Read — Consultando dados import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.select // Todos os usuários ativos val usuariosAtivos = transaction { Usuarios.selectAll() .where { Usuarios.ativo eq true } .map { row -\u0026gt; UsuarioDTO( id = row[Usuarios.id], nome = row[Usuarios.nome], email = row[Usuarios.email] ) } } // Busca com join val pedidosComUsuario = transaction { (Pedidos innerJoin Usuarios) .selectAll() .where { Pedidos.status eq \u0026#34;PENDENTE\u0026#34; } .map { row -\u0026gt; PedidoResumo( pedidoId = row[Pedidos.id], nomeUsuario = row[Usuarios.nome], total = row[Pedidos.total] ) } } Update — Atualizando registros import org.jetbrains.exposed.sql.update transaction { Usuarios.update({ Usuarios.id eq 1 }) { it[nome] = \u0026#34;João Silva Junior\u0026#34; it[ativo] = false } } Delete — Removendo registros import org.jetbrains.exposed.sql.deleteWhere transaction { Pedidos.deleteWhere { Pedidos.status eq \u0026#34;CANCELADO\u0026#34; } } Abordagem DAO — Estilo ORM Se você prefere trabalhar com objetos no estilo ORM tradicional, o Exposed oferece a camada DAO:\nimport org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntityClass import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.IntIdTable // Tabela precisa usar IntIdTable para DAO object UsuariosTable : IntIdTable(\u0026#34;usuarios\u0026#34;) { val nome = varchar(\u0026#34;nome\u0026#34;, 100) val email = varchar(\u0026#34;email\u0026#34;, 255).uniqueIndex() val ativo = bool(\u0026#34;ativo\u0026#34;).default(true) val criadoEm = datetime(\u0026#34;criado_em\u0026#34;) } class Usuario(id: EntityID\u0026lt;Int\u0026gt;) : IntEntity(id) { companion object : IntEntityClass\u0026lt;Usuario\u0026gt;(UsuariosTable) var nome by UsuariosTable.nome var email by UsuariosTable.email var ativo by UsuariosTable.ativo var criadoEm by UsuariosTable.criadoEm } Com DAO, as operações são mais orientadas a objetos:\ntransaction { // Criar val usuario = Usuario.new { nome = \u0026#34;Pedro Costa\u0026#34; email = \u0026#34;pedro@email.com\u0026#34; ativo = true criadoEm = LocalDateTime.now() } // Ler val encontrado = Usuario.findById(1) val ativos = Usuario.find { UsuariosTable.ativo eq true } // Atualizar encontrado?.nome = \u0026#34;Pedro Costa Junior\u0026#34; // Deletar encontrado?.delete() } DSL vs DAO: Quando usar cada um? Aspecto DSL DAO Estilo Funcional, parecido com SQL Orientado a objetos Performance Ligeiramente mais rápido Overhead do mapeamento Queries complexas Excelente Limitado CRUD simples Verboso Conciso Lazy loading Não Sim Melhor para Relatórios, queries complexas CRUDs, domínios ricos Na prática, muitos projetos combinam as duas abordagens — DAO para operações simples e DSL para queries complexas.\nIntegração com Ktor O Exposed combina perfeitamente com Ktor, o framework web da JetBrains:\nimport io.ktor.server.application.* import io.ktor.server.response.* import io.ktor.server.routing.* import org.jetbrains.exposed.sql.transactions.transaction fun Application.configurarRotas() { routing { get(\u0026#34;/usuarios\u0026#34;) { val usuarios = transaction { Usuarios.selectAll() .where { Usuarios.ativo eq true } .map { row -\u0026gt; mapOf( \u0026#34;id\u0026#34; to row[Usuarios.id], \u0026#34;nome\u0026#34; to row[Usuarios.nome], \u0026#34;email\u0026#34; to row[Usuarios.email] ) } } call.respond(usuarios) } } } Para projetos maiores com Spring Boot, confira nosso tutorial completo de Kotlin com Spring Boot.\nTransações e tratamento de erros O Exposed exige que todas as operações de banco sejam executadas dentro de um bloco transaction. Isso garante atomicidade:\nimport org.jetbrains.exposed.sql.transactions.transaction try { transaction { // Todas as operações aqui são atômicas val pedidoId = Pedidos.insertAndGetId { it[usuarioId] = 1 it[total] = 299.90.toBigDecimal() it[status] = \u0026#34;CRIADO\u0026#34; it[criadoEm] = LocalDateTime.now() } Usuarios.update({ Usuarios.id eq 1 }) { it[ativo] = true } // Se algo falhar aqui, tudo acima é revertido } } catch (e: Exception) { println(\u0026#34;Erro na transação: ${e.message}\u0026#34;) } Para operações assíncronas com coroutines e Flow, o Exposed oferece newSuspendedTransaction:\nimport org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction suspend fun buscarUsuarioAsync(id: Int): UsuarioDTO? { return newSuspendedTransaction { Usuarios.selectAll() .where { Usuarios.id eq id } .firstOrNull() ?.let { UsuarioDTO(it[Usuarios.id], it[Usuarios.nome], it[Usuarios.email]) } } } Exposed vs Hibernate/JPA Se você vem do mundo Java, provavelmente já usou Hibernate. Veja como o Exposed se compara:\nAspecto Exposed Hibernate/JPA Linguagem Kotlin nativo Java (funciona em Kotlin) Configuração Mínima, tudo em código XML ou anotações extensas Type safety Total (verificado em compilação) Parcial (JPQL é string) Curva de aprendizado Baixa para devs Kotlin Moderada a alta Ecossistema Crescente Maduro e vasto Null safety Integrado Requer cuidado extra Coroutines Suporte nativo Requer adaptação Boas práticas Use HikariCP para connection pooling — nunca conecte diretamente ao banco em produção Prefira DSL para queries complexas — a type safety evita erros em runtime Separe definições de tabelas em um pacote database.tables Use newSuspendedTransaction em projetos com coroutines para não bloquear threads Teste com banco em memória (H2) para testes unitários rápidos — veja nosso guia de testes em Kotlin Conclusão O Exposed é uma excelente alternativa ao Hibernate para projetos Kotlin. Com sua DSL type-safe, suporte a coroutines e manutenção pela JetBrains, ele oferece uma experiência de desenvolvimento muito mais natural para quem trabalha com Kotlin.\nSe você está começando um novo projeto backend com Ktor ou quer uma alternativa mais leve para o Spring Boot, o Exposed merece um lugar na sua lista de ferramentas.\nPara continuar aprendendo, explore nosso Guia de Kotlin para Backend e o Glossário de Kotlin.\nSe você está usando Exposed dentro de uma API web, veja também o tutorial de Ktor com Exposed para conectar routing, serialização e persistência no mesmo projeto. Se você trabalha com múltiplas linguagens no backend, vale comparar abordagens de acesso a banco: Python tem o SQLAlchemy como ORM de referência, enquanto Rust aposta no Diesel e SQLx para acesso type-safe a bancos.\n","permalink":"https://kotlin.dev.br/blog/kotlin-exposed-orm-framework-sql/","summary":"\u003cp\u003eQuando se fala em acesso a banco de dados no ecossistema Kotlin, o Hibernate costuma ser a primeira opção por causa da integração com \u003ca href=\"/blog/kotlin-spring-boot/\"\u003eSpring Boot\u003c/a\u003e. Mas existe uma alternativa 100% Kotlin, criada pela própria JetBrains: o \u003cstrong\u003eExposed\u003c/strong\u003e. Neste tutorial, vamos explorar como ele funciona, suas duas abordagens (DSL e DAO), e por que ele pode ser a melhor escolha para o seu próximo projeto. Para uma visão mais aplicada com PostgreSQL, pool de conexões e migrations, leia também \u003ca href=\"/tutoriais/kotlin-postgresql-backend/\"\u003eKotlin com PostgreSQL no backend\u003c/a\u003e.\u003c/p\u003e","title":"Kotlin Exposed ORM: Como Usar o Framework SQL da JetBrains | Kotlin Brasil"},{"content":"Se você já trabalhou com extension functions em Kotlin, sabe como elas tornam o código mais expressivo. Mas e quando uma função precisa de múltiplos contextos ao mesmo tempo? É aí que entram os Context Receivers e sua evolução, os Context Parameters. Neste guia, vamos explorar como essas funcionalidades transformam a forma de escrever código Kotlin.\nO que são Context Receivers? Context Receivers foram introduzidos experimentalmente no Kotlin 1.6.20 como uma forma de declarar que uma função precisa de um ou mais contextos implícitos para ser chamada. Diferente de extension functions, que possuem apenas um receiver, os context receivers permitem múltiplos.\nA ideia central é simples: em vez de passar dependências explicitamente como parâmetros, você declara que a função requer um determinado contexto para funcionar.\nSintaxe básica context(LoggerContext) fun processarPedido(pedido: Pedido) { log(\u0026#34;Processando pedido ${pedido.id}\u0026#34;) // lógica de processamento } interface LoggerContext { fun log(mensagem: String) } Para chamar essa função, o chamador precisa estar em um escopo onde LoggerContext esteja disponível:\nclass ServicoDeVendas : LoggerContext { override fun log(mensagem: String) { println(\u0026#34;[VENDAS] $mensagem\u0026#34;) } fun vender(pedido: Pedido) { processarPedido(pedido) // funciona! LoggerContext está no escopo } } Context Receivers vs Extension Functions Você pode estar pensando: \u0026ldquo;Isso parece uma extension function\u0026rdquo;. E de fato a motivação é semelhante, mas existem diferenças cruciais:\nAspecto Extension Function Context Receiver Receivers Apenas 1 Múltiplos Acesso ao this Sim, do receiver Sim, de cada contexto Uso primário Adicionar métodos a tipos Injeção de contexto implícito Combinação Difícil combinar múltiplos Natural com múltiplos contextos Exemplo prático com múltiplos contextos interface TransactionContext { fun \u0026lt;T\u0026gt; executarTransacao(bloco: () -\u0026gt; T): T } interface NotificacaoContext { fun notificar(usuario: String, mensagem: String) } context(TransactionContext, NotificacaoContext, LoggerContext) fun transferirSaldo(origem: Conta, destino: Conta, valor: Double) { log(\u0026#34;Iniciando transferência de R$$valor\u0026#34;) executarTransacao { origem.debitar(valor) destino.creditar(valor) } notificar(origem.titular, \u0026#34;Transferência de R$$valor realizada\u0026#34;) log(\u0026#34;Transferência concluída com sucesso\u0026#34;) } Esse código é limpo, sem precisar passar cada dependência como parâmetro. Se você trabalha com Python e decorators, vai notar uma semelhança conceitual: ambos permitem injetar comportamento de forma declarativa, embora com mecanismos bem diferentes.\nDe Context Receivers para Context Parameters A equipe do Kotlin percebeu que a implementação original de context receivers tinha limitações. Por isso, a partir do Kotlin 2.0+, a funcionalidade está evoluindo para Context Parameters — uma abordagem mais refinada e segura.\nPrincipais diferenças // Context Receivers (experimental, Kotlin 1.6.20+) context(LoggerContext) fun processarPedido(pedido: Pedido) { ... } // Context Parameters (evolução futura) fun processarPedido(context logger: LoggerContext, pedido: Pedido) { ... } Com context parameters, o contexto é declarado de forma mais explícita na assinatura da função, tornando o código mais previsível e fácil de entender. As vantagens incluem:\nNomeação explícita: cada contexto tem um nome, evitando ambiguidades Melhor inferência de tipos: o compilador K2 trabalha melhor com essa sintaxe Compatibilidade com IDE: melhor autocomplete e navegação no IntelliJ IDEA Casos de uso práticos 1. Injeção de dependências leve Context receivers oferecem uma forma de injeção de dependências sem frameworks pesados como Koin ou Dagger:\ninterface RepositorioPedidos { fun buscarPorId(id: Long): Pedido? fun salvar(pedido: Pedido): Pedido } interface ServicoPagamento { fun processar(valor: Double, metodo: MetodoPagamento): ResultadoPagamento } context(RepositorioPedidos, ServicoPagamento, LoggerContext) fun finalizarCompra(pedidoId: Long, metodo: MetodoPagamento): ResultadoCompra { val pedido = buscarPorId(pedidoId) ?: error(\u0026#34;Pedido não encontrado\u0026#34;) log(\u0026#34;Processando pagamento para pedido $pedidoId\u0026#34;) val resultado = processar(pedido.total, metodo) if (resultado.sucesso) { salvar(pedido.copy(status = Status.PAGO)) log(\u0026#34;Pedido $pedidoId pago com sucesso\u0026#34;) } return ResultadoCompra(pedidoId, resultado) } 2. Construção de DSLs mais expressivas Se você já leu nosso guia sobre DSLs em Kotlin, sabe que lambdas com receiver são essenciais. Context receivers levam isso a outro nível:\ninterface HtmlContext { fun tag(nome: String, conteudo: String) } interface CssContext { fun estilo(seletor: String, propriedades: Map\u0026lt;String, String\u0026gt;) } context(HtmlContext, CssContext) fun componenteCartao(titulo: String, descricao: String) { estilo(\u0026#34;.cartao\u0026#34;, mapOf( \u0026#34;border-radius\u0026#34; to \u0026#34;8px\u0026#34;, \u0026#34;padding\u0026#34; to \u0026#34;16px\u0026#34;, \u0026#34;box-shadow\u0026#34; to \u0026#34;0 2px 4px rgba(0,0,0,0.1)\u0026#34; )) tag(\u0026#34;div\u0026#34;, \u0026#34;\u0026#34;\u0026#34; \u0026lt;h3\u0026gt;$titulo\u0026lt;/h3\u0026gt; \u0026lt;p\u0026gt;$descricao\u0026lt;/p\u0026gt; \u0026#34;\u0026#34;\u0026#34;) } 3. Logging e monitoramento com contexto Uma aplicação prática e comum é adicionar contexto de observabilidade sem poluir assinaturas de funções:\ninterface TracingContext { val traceId: String fun span(nome: String, bloco: () -\u0026gt; Unit) } context(TracingContext, LoggerContext) fun processarEvento(evento: Evento) { span(\u0026#34;processar-evento\u0026#34;) { log(\u0026#34;[$traceId] Evento recebido: ${evento.tipo}\u0026#34;) // processamento do evento } } Como habilitar Context Receivers hoje Para experimentar context receivers no seu projeto, adicione ao build.gradle.kts:\ntasks.withType\u0026lt;KotlinCompile\u0026gt; { compilerOptions { freeCompilerArgs.add(\u0026#34;-Xcontext-receivers\u0026#34;) } } Atenção: Context receivers ainda são experimentais. A API pode mudar em versões futuras do Kotlin. Para projetos em produção, avalie cuidadosamente e acompanhe as notas de release oficiais.\nRelação com Coroutines e Scope Functions Se você usa coroutines, já está familiarizado com o conceito de escopo contextual — CoroutineScope funciona de maneira análoga. E as scope functions (let, run, with, apply, also) são primas próximas, operando com receivers implícitos.\nContext receivers estendem esse padrão, permitindo que qualquer função declare seus requisitos contextuais de forma tipada e segura.\nBoas práticas Use com moderação: não transforme todo parâmetro em context receiver — use apenas para dependências transversais (logging, transações, configuração) Prefira interfaces: declare contextos como interfaces, não classes concretas, facilitando testes Documente os contextos: como a dependência é implícita, documentar qual contexto é necessário ajuda a manutenibilidade Acompanhe a evolução: migre para context parameters quando a funcionalidade estabilizar Conclusão Context Receivers e Context Parameters representam uma evolução natural do sistema de receivers do Kotlin. Eles resolvem o problema de injeção de múltiplos contextos de forma elegante, complementando as extension functions e as sealed classes no arsenal do desenvolvedor Kotlin.\nEmbora ainda experimentais, já mostram como o Kotlin continua inovando para tornar o código mais expressivo e seguro. Fique de olho nas próximas versões e comece a experimentar nos seus projetos pessoais.\nPara se aprofundar na linguagem, confira nosso Guia Completo de Kotlin e o Glossário de Kotlin.\nSe o conceito de injeção de contexto te interessou, vale explorar como outras linguagens resolvem problemas semelhantes: Go usa o pacote context para propagação de valores entre funções, enquanto Rust resolve isso com traits e generics no sistema de tipos.\n","permalink":"https://kotlin.dev.br/blog/kotlin-context-receivers-parameters/","summary":"\u003cp\u003eSe você já trabalhou com \u003ca href=\"/blog/extension-functions-kotlin/\"\u003eextension functions\u003c/a\u003e em Kotlin, sabe como elas tornam o código mais expressivo. Mas e quando uma função precisa de \u003cstrong\u003emúltiplos contextos\u003c/strong\u003e ao mesmo tempo? É aí que entram os \u003cstrong\u003eContext Receivers\u003c/strong\u003e e sua evolução, os \u003cstrong\u003eContext Parameters\u003c/strong\u003e. Neste guia, vamos explorar como essas funcionalidades transformam a forma de escrever código Kotlin.\u003c/p\u003e\n\u003ch2 id=\"o-que-são-context-receivers\"\u003eO que são Context Receivers?\u003c/h2\u003e\n\u003cp\u003eContext Receivers foram introduzidos experimentalmente no Kotlin 1.6.20 como uma forma de declarar que uma função precisa de um ou mais \u003cstrong\u003econtextos implícitos\u003c/strong\u003e para ser chamada. Diferente de extension functions, que possuem apenas um receiver, os context receivers permitem múltiplos.\u003c/p\u003e","title":"Kotlin Context Receivers e Context Parameters: Guia Prático | Kotlin Brasil"},{"content":"Sobre a vagaA Wellhub busca uma pessoa Staff Software Engineer Fullstack para o time PEX, em uma posição remota no Brasil, com possibilidade de atuação em São Paulo.\nTecnologiasKotlin, Java e JVMReact e TypeScriptNode.jsAWSMicroservices e micro-frontendsPerfilSenioridade sênior/staff em engenharia de software.Experiência em desenvolvimento fullstack, atuando em backend e frontend.Vivência com arquiteturas distribuídas e serviços em nuvem. ","permalink":"https://kotlin.dev.br/vagas/yy6tfcq21h3j4rb5-wellhub-staff-software-engineer-fullstack-pex/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Wellhub busca uma pessoa \u003cstrong\u003eStaff Software Engineer Fullstack\u003c/strong\u003e para o time PEX, em uma posição remota no Brasil, com possibilidade de atuação em São Paulo.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java e JVM\u003c/li\u003e\u003cli\u003eReact e TypeScript\u003c/li\u003e\u003cli\u003eNode.js\u003c/li\u003e\u003cli\u003eAWS\u003c/li\u003e\u003cli\u003eMicroservices e micro-frontends\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003ePerfil\u003c/h3\u003e\u003cul\u003e\u003cli\u003eSenioridade sênior/staff em engenharia de software.\u003c/li\u003e\u003cli\u003eExperiência em desenvolvimento fullstack, atuando em backend e frontend.\u003c/li\u003e\u003cli\u003eVivência com arquiteturas distribuídas e serviços em nuvem.\u003c/li\u003e\u003c/ul\u003e","title":"Staff Software Engineer Fullstack | PEX"},{"content":"Em 2026, a decisão entre Kotlin nativo e Flutter cross-platform ficou mais complexa — e mais interessante. Com o Kotlin Multiplatform (KMP) estável e o Flutter 3.x maduro, a distinção entre \u0026ldquo;nativo\u0026rdquo; e \u0026ldquo;híbrido\u0026rdquo; já não é tão clara. Este guia compara as duas abordagens com foco no que importa para times e devs brasileiros.\nO que estamos comparando (de verdade) Antes de qualquer coisa, vamos alinhar os termos:\nKotlin nativo = Jetpack Compose para Android + opcionalmente KMP para compartilhar lógica com iOS Flutter = Framework cross-platform do Google com engine própria (Skia/Impeller) e linguagem Dart Kotlin Multiplatform (KMP) = Compartilha código Kotlin entre Android, iOS, Desktop e Web O ponto-chave: Kotlin em 2026 não é só \u0026ldquo;Android nativo\u0026rdquo; — com KMP e Compose Multiplatform, também é uma solução multiplataforma. Então estamos comparando duas abordagens cross-platform com filosofias distintas.\nTabela comparativa Critério Kotlin (Nativo + KMP) Flutter (Dart) Filosofia UI nativa por plataforma, lógica compartilhada Tudo compartilhado (UI + lógica) Linguagem Kotlin Dart Rendering Componentes nativos do SO Engine própria (Impeller) Compartilhamento de código 50-70% (lógica) com KMP 80-95% (tudo) com Flutter Performance Nativa (sem overhead) Quase nativa (engine compilada) Look \u0026amp; feel 100% nativo em cada plataforma Personalizado (Material/Cupertino) Tamanho do time Pode precisar de dev iOS separado Um time entrega tudo Tamanho do APK Menor (~5-15MB) Maior (~15-30MB base) Hot reload Sim (Compose preview) Sim (excelente, mais rápido) Plataformas Android, iOS, Desktop, Web Android, iOS, Web, Desktop, Embedded Maturidade Compose: 3 anos / KMP: estável Flutter: 7 anos, maduro Quando Kotlin nativo é a melhor escolha 1. Performance é crítica Aplicativos que exigem performance máxima — como apps de streaming, jogos casuales, ou apps com animações pesadas — se beneficiam do acesso direto a APIs nativas:\n// Kotlin - acesso direto a APIs nativas do Android @Composable fun CameraPreview(onImageCaptured: (Bitmap) -\u0026gt; Unit) { val context = LocalContext.current val cameraProvider = remember { ProcessCameraProvider.getInstance(context) } AndroidView( factory = { ctx -\u0026gt; PreviewView(ctx).apply { implementationMode = PreviewView.ImplementationMode.COMPATIBLE } }, modifier = Modifier.fillMaxSize() ) } Acesso direto a hardware (câmera, Bluetooth, sensores) é sempre mais simples e performático no nativo. Veja nosso guia de performance Kotlin para técnicas avançadas.\n2. UX pixel-perfect por plataforma Se seu app precisa parecer genuinamente Android no Android e genuinamente iOS no iOS, Kotlin nativo com Compose + SwiftUI entrega isso naturalmente. Flutter consegue simular, mas usuários atentos notam diferenças sutis em gestos, transições e feedback tátil.\n3. Ecossistema Android profundo Para apps que usam intensamente o ecossistema Android — WorkManager, Widgets, Wear OS, Android Auto — Kotlin nativo é a única opção realista. Integrações com Jetpack libraries são de primeira classe:\n// Kotlin - integração profunda com Jetpack @HiltViewModel class PedidosViewModel @Inject constructor( private val repository: PedidoRepository, private val savedStateHandle: SavedStateHandle ) : ViewModel() { val pedidos = repository.observarPedidos() .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) fun cancelarPedido(id: Long) { viewModelScope.launch { repository.cancelar(id) } } } Confira nosso guia de arquitetura MVVM e o tutorial de ViewModel para aprofundar.\n4. Time com experiência Android Se seu time já domina Android e Kotlin, adotar KMP para compartilhar lógica com iOS é uma evolução natural. A curva de aprendizado é mínima — a linguagem e as ferramentas são as mesmas. Consulte nosso guia de KMP mobile para começar.\nQuando Flutter é a melhor escolha 1. Time pequeno, duas plataformas O argumento mais forte do Flutter: um dev entrega para Android e iOS ao mesmo tempo com 80-95% de código compartilhado (incluindo UI). Para startups e times enxutos, isso é decisivo:\n// Flutter/Dart - uma UI para todas as plataformas class CartaoPedido extends StatelessWidget { final Pedido pedido; const CartaoPedido({required this.pedido}); @override Widget build(BuildContext context) { return Card( margin: const EdgeInsets.all(8), child: ListTile( leading: Icon( pedido.entregue ? Icons.check_circle : Icons.pending, color: pedido.entregue ? Colors.green : Colors.orange, ), title: Text(pedido.descricao), subtitle: Text(\u0026#39;R\\$ ${pedido.valor.toStringAsFixed(2)}\u0026#39;), trailing: Text(pedido.data), ), ); } } 2. MVP e validação rápida Se você precisa validar uma ideia no mercado rapidamente, Flutter permite prototipar e lançar em ambas as plataformas mais rápido. O hot reload do Flutter ainda é considerado o melhor da indústria.\n3. UI customizada e única Se seu app tem um design próprio que não segue Material Design nem iOS guidelines — como um app de meditação, jogo ou app com identidade visual forte — Flutter pode ser vantajoso, já que você controla cada pixel independente da plataforma.\n4. Web + Mobile com mesmo codebase Flutter Web melhorou significativamente e permite entregar web + mobile com o mesmo codebase. Kotlin ainda não tem paridade nessa frente (Compose for Web é experimental).\nPerformance: a verdade em 2026 A diferença de performance entre Kotlin nativo e Flutter em 2026 é marginal para 90% dos apps:\nInicialização: Kotlin nativo é ~200-400ms mais rápido no cold start Scrolling: Praticamente idêntico com o engine Impeller do Flutter Animações: Ambos conseguem 60fps consistente em devices modernos Memória: Kotlin nativo usa 15-25% menos RAM em média A verdade: se performance fosse o único critério, nativo sempre venceria. Mas a diferença é imperceptível para o usuário em apps de negócios, e-commerce, delivery, fintech e redes sociais.\nKotlin Multiplatform vs Flutter: o verdadeiro debate de 2026 A comparação mais relevante em 2026 não é \u0026ldquo;Kotlin Android vs Flutter\u0026rdquo; — é \u0026ldquo;KMP vs Flutter\u0026rdquo; como soluções multiplataforma:\nAspecto KMP + Compose Multiplatform Flutter Compartilha lógica ✅ ✅ Compartilha UI ✅ (Compose Multiplatform) ✅ UI nativa ✅ (opção de usar SwiftUI/Compose) ❌ (engine própria) Reuso em backend ✅ (Ktor, Spring Boot) ❌ (Dart no backend é raro) Maturidade KMP estável, CMP em beta Estável há 7 anos Comunidade Crescendo rápido Grande e estabelecida A vantagem única do Kotlin: a mesma linguagem no mobile, backend e desktop. Se sua empresa tem backend em Ktor ou Spring Boot, compartilhar modelos e lógica entre backend e mobile é natural com KMP.\nMercado de trabalho no Brasil Vagas Kotlin (Android + KMP) Volume: Alto — Android domina 82% do mercado brasileiro Salário sênior: R$ 18.000 - R$ 28.000/mês (remoto) Tendência: Crescente, especialmente vagas pedindo KMP Perfil: Maioria das vagas em fintechs, delivery e grandes empresas Vagas Flutter Volume: Crescente — mas ~40% menos que Android nativo Salário sênior: R$ 15.000 - R$ 25.000/mês (remoto) Tendência: Estável, popular em startups e agências Perfil: Startups, agências digitais, projetos com budget limitado Para dados detalhados do mercado brasileiro, veja nossa seção de carreira Kotlin e o artigo sobre vagas remotas.\nDica de carreira Saber Kotlin + Flutter não é redundante — é complementar. O dev que domina Kotlin nativo e entende Flutter consegue recomendar a abordagem certa para cada projeto. Isso tem muito valor em posições de liderança técnica.\nConclusão — Qual escolher? Escolha Kotlin nativo (+ KMP) se:\n✅ Performance e UX nativa são prioridades ✅ Seu time tem experiência Android ✅ Você quer reaproveitar código no backend (Ktor/Spring Boot) ✅ O app precisa de integração profunda com APIs nativas do SO ✅ A empresa tem devs iOS que podem consumir módulos KMP Escolha Flutter se:\n✅ Time pequeno que precisa entregar para duas plataformas rápido ✅ MVP ou validação de produto ✅ Design customizado que não segue guidelines padrão ✅ Web + mobile com o mesmo codebase ✅ Orçamento limitado para desenvolvimento Em 2026, não existe resposta errada — ambas são tecnologias maduras e bem suportadas. A decisão deve ser baseada no seu contexto: tamanho do time, prazo, requisitos de UX e stack existente.\nFAQ — Perguntas frequentes Flutter é mais rápido que Kotlin nativo? Não. Kotlin nativo tem vantagem em cold start e uso de memória. Mas a diferença de performance no dia a dia é imperceptível para a maioria dos apps. O Impeller engine do Flutter 3.x fechou a maior parte do gap que existia.\nKotlin Multiplatform substitui Flutter? São abordagens diferentes. KMP compartilha lógica mantendo UI nativa; Flutter compartilha tudo (UI + lógica) com engine própria. KMP é ideal para quem quer UX nativa; Flutter é ideal para quem quer maximizar código compartilhado com time enxuto.\nQual tem mais vagas no Brasil? Kotlin (Android nativo) tem ~40% mais vagas que Flutter no Brasil, refletindo a dominância do Android no mercado brasileiro. Mas vagas Flutter crescem consistentemente, especialmente em startups. Confira vagas Kotlin no Brasil para dados atualizados.\nDá pra usar Kotlin e Flutter juntos? Tecnicamente sim — você pode integrar módulos Kotlin nativos em um app Flutter usando platform channels. Mas na prática é raro, pois aumenta a complexidade. Mais comum é escolher uma abordagem e seguir com ela.\nPara quem está começando: Kotlin ou Flutter? Se quer focar no mercado brasileiro e maximizar oportunidades, comece com Kotlin — Android domina aqui. Depois, aprenda KMP para expandir para iOS. Se tem urgência em lançar um app em duas plataformas com um time de um dev, Flutter é a escolha pragmática. Comece com nosso primeiro programa em Kotlin ou tutorial de Jetpack Compose.\nExplore mais comparações em nosso portal de comparações e confira nossos tutoriais práticos para começar a desenvolver. Para quem se interessa por outras linguagens no backend e além do mobile, visite o Go Brasil, o Rust Brasil e o Python Brasil.\n","permalink":"https://kotlin.dev.br/blog/kotlin-vs-flutter-dart-nativo-hibrido/","summary":"\u003cp\u003eEm 2026, a decisão entre Kotlin nativo e Flutter cross-platform ficou mais complexa — e mais interessante. Com o Kotlin Multiplatform (KMP) estável e o Flutter 3.x maduro, \u003cstrong\u003ea distinção entre \u0026ldquo;nativo\u0026rdquo; e \u0026ldquo;híbrido\u0026rdquo; já não é tão clara\u003c/strong\u003e. Este guia compara as duas abordagens com foco no que importa para times e devs brasileiros.\u003c/p\u003e\n\u003ch2 id=\"o-que-estamos-comparando-de-verdade\"\u003eO que estamos comparando (de verdade)\u003c/h2\u003e\n\u003cp\u003eAntes de qualquer coisa, vamos alinhar os termos:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eKotlin nativo\u003c/strong\u003e = Jetpack Compose para Android + opcionalmente KMP para compartilhar lógica com iOS\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eFlutter\u003c/strong\u003e = Framework cross-platform do Google com engine própria (Skia/Impeller) e linguagem Dart\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eKotlin Multiplatform (KMP)\u003c/strong\u003e = Compartilha código Kotlin entre Android, iOS, Desktop e Web\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eO ponto-chave: \u003cstrong\u003eKotlin em 2026 não é só \u0026ldquo;Android nativo\u0026rdquo;\u003c/strong\u003e — com KMP e Compose Multiplatform, também é uma solução multiplataforma. Então estamos comparando duas abordagens cross-platform com filosofias distintas.\u003c/p\u003e","title":"Kotlin vs Flutter: Nativo ou Híbrido em 2026? | Kotlin Brasil"},{"content":"Em 2026, o cenário mobile mudou. Kotlin Multiplatform (KMP) saiu de beta, SwiftUI amadureceu, e a pergunta \u0026ldquo;Kotlin ou Swift?\u0026rdquo; ganhou camadas novas. Se você é dev mobile no Brasil e está escolhendo onde investir sua carreira, este guia prático vai te ajudar a decidir.\nPor que essa comparação importa em 2026 Historicamente, a resposta era simples: Kotlin para Android, Swift para iOS. Mas com o Kotlin Multiplatform permitindo compartilhar lógica entre Android e iOS, e o SwiftUI facilitando UIs declarativas no ecossistema Apple, as fronteiras ficaram menos claras.\nAlém disso, o mercado brasileiro tem particularidades — a participação de Android no Brasil passa de 80%, o que muda completamente o cálculo de carreira.\nTabela comparativa atualizada Critério Kotlin 2.1 (2026) Swift 6 (2026) Plataforma principal Android + multiplataforma iOS, macOS, watchOS, tvOS UI declarativa Jetpack Compose + CMP SwiftUI Null safety ? (nullable types) Optionals (?, !) Concorrência Coroutines + Flow async/await + Actors Multiplataforma KMP (Android, iOS, Desktop, Web) Apenas ecossistema Apple IDE IntelliJ IDEA / Android Studio Xcode Backend Ktor, Spring Boot Vapor (pequena comunidade) Market share Brasil ~82% (Android) ~18% (iOS) Vagas Brasil Abundantes Menos vagas, salários mais altos Open source Sim (Apache 2.0) Sim (Apache 2.0) Comparação de sintaxe em 2026 As duas linguagens são surpreendentemente parecidas na sintaxe básica. Ambas foram inspiradas em conceitos modernos de linguagens de programação.\nDeclaração de variáveis e null safety // Kotlin val nome: String = \u0026#34;Kotlin Brasil\u0026#34; // imutável var contador: Int = 0 // mutável val email: String? = null // nullable explícito // Safe call + Elvis operator val tamanho = email?.length ?: 0 // Swift let nome: String = \u0026#34;Kotlin Brasil\u0026#34; // imutável var contador: Int = 0 // mutável let email: String? = nil // Optional // Optional chaining + nil coalescing let tamanho = email?.count ?? 0 A abordagem é quase idêntica. Se você sabe uma, aprender a outra é questão de dias.\nConcorrência moderna // Kotlin Coroutines suspend fun buscarPerfil(userId: String): Perfil { return coroutineScope { val dados = async { api.getDados(userId) } val foto = async { api.getFoto(userId) } Perfil(dados.await(), foto.await()) } } // Swift async/await func buscarPerfil(userId: String) async throws -\u0026gt; Perfil { async let dados = api.getDados(userId) async let foto = api.getFoto(userId) return try await Perfil(dados, foto) } Novamente, muito semelhantes. Swift adotou async/await inspirado no modelo de Kotlin Coroutines (e vice-versa — ambos se influenciam mutuamente).\nUI declarativa // Jetpack Compose (Kotlin) @Composable fun CartaoUsuario(usuario: Usuario) { Card(modifier = Modifier.padding(16.dp)) { Column(modifier = Modifier.padding(12.dp)) { Text( text = usuario.nome, style = MaterialTheme.typography.titleLarge ) Text( text = usuario.cargo, color = MaterialTheme.colorScheme.onSurfaceVariant ) } } } // SwiftUI struct CartaoUsuario: View { let usuario: Usuario var body: some View { VStack(alignment: .leading, spacing: 8) { Text(usuario.nome) .font(.title2) Text(usuario.cargo) .foregroundColor(.secondary) } .padding() .background(RoundedRectangle(cornerRadius: 12).fill(.background)) } } Jetpack Compose e SwiftUI seguem o mesmo paradigma declarativo. A transição entre os dois é natural pra quem já domina um deles.\nO fator Kotlin Multiplatform A grande mudança em 2026 é que o Kotlin Multiplatform (KMP) atingiu estabilidade. Agora você pode:\nCompartilhar lógica de negócio entre Android e iOS (networking, cache, validação) Manter UI nativa em cada plataforma (Compose no Android, SwiftUI no iOS) Usar Compose Multiplatform para compartilhar até a UI entre plataformas Isso muda o cálculo: um dev Kotlin pode entregar para Android e iOS ao mesmo tempo, algo que um dev Swift puro não consegue.\n// KMP - Código compartilhado entre Android e iOS // commonMain/src/ class PedidoRepository(private val api: PedidoApi) { suspend fun buscarPedidos(userId: String): List\u0026lt;Pedido\u0026gt; { return api.getPedidos(userId) .filter { it.status != StatusPedido.CANCELADO } .sortedByDescending { it.data } } } Essa mesma classe roda no Android e no iOS sem alteração. A camada de UI fica nativa em cada plataforma. Veja nosso tutorial de KMP para um guia prático.\nMercado de trabalho no Brasil Aqui é onde a conversa fica séria para quem mora no Brasil:\nKotlin no mercado brasileiro Android domina com ~82% de market share no Brasil Vagas de dev Android/Kotlin são 3-4x mais numerosas que iOS/Swift Salário dev Kotlin sênior: R$ 18.000 - R$ 28.000/mês (remoto) KMP está criando vagas de \u0026ldquo;mobile multiplataforma\u0026rdquo; que antes não existiam Empresas como iFood, Nubank, Globo e BTG usam Kotlin extensivamente Swift no mercado brasileiro iOS tem ~18% do mercado, mas concentrado em público de maior poder aquisitivo Menos vagas, mas geralmente com salários 10-20% superiores Salário dev iOS sênior: R$ 20.000 - R$ 32.000/mês (remoto) Startups focadas em público premium tendem a priorizar iOS Menos concorrência por vaga (menos devs Swift no Brasil) Para uma análise detalhada dos salários, confira nossos artigos sobre salário de dev Android Kotlin e salários Kotlin no Brasil.\nA estratégia do dev mobile completo O cenário ideal em 2026: aprenda Kotlin como linguagem principal, domine KMP, e tenha conhecimento básico de Swift/SwiftUI. Assim você consegue:\nAtender a demanda Android (maioria das vagas) Entregar lógica compartilhada para iOS via KMP Fazer ajustes na camada iOS quando necessário Essa combinação é rara no mercado brasileiro e te coloca em uma posição privilegiada. Veja nosso roadmap de carreira Android para planejar seus próximos passos.\nEcossistema e ferramentas Kotlin IDE: Android Studio / IntelliJ IDEA (ambos excelentes para Kotlin) UI: Jetpack Compose (estável) + Compose Multiplatform Networking: Ktor Client (multiplataforma) DI: Koin (multiplataforma) ou Hilt (Android) Testes: JUnit5 + MockK ou Kotest Backend: Ktor, Spring Boot Swift IDE: Xcode (a única opção real) UI: SwiftUI (maduro em 2026) Networking: URLSession nativo ou Alamofire DI: Swift Dependencies ou manual Testes: XCTest + Swift Testing Backend: Vapor (comunidade menor) O ecossistema Kotlin é mais amplo porque a linguagem atende mais plataformas. Swift é mais focado mas profundamente integrado ao ecossistema Apple.\nConclusão — Qual escolher? Escolha Kotlin se:\n✅ Você quer maximizar oportunidades de emprego no Brasil ✅ Quer atender Android (82% do mercado BR) como prioridade ✅ Tem interesse em multiplataforma (KMP + Compose Multiplatform) ✅ Também quer atuar em backend (Ktor, Spring Boot) ✅ Busca versatilidade de carreira Escolha Swift se:\n✅ Quer se especializar no ecossistema Apple ✅ Trabalha (ou quer trabalhar) em empresas focadas em público premium ✅ Prefere menos concorrência por vaga, mesmo com menos vagas disponíveis ✅ Tem um Mac e prefere o workflow Xcode/Apple A melhor resposta em 2026: aprenda Kotlin como base, use KMP para multiplataforma, e adicione Swift como skill complementar. É a combinação mais valiosa no mercado mobile brasileiro.\nFAQ — Perguntas frequentes Qual paga mais no Brasil: Kotlin ou Swift? Dev iOS/Swift tende a ganhar 10-20% a mais em posições equivalentes, mas há significativamente menos vagas. No total de oportunidades × salário, Kotlin oferece melhor retorno para a maioria dos devs brasileiros. Confira dados atualizados em nossa seção de carreira.\nKMP vai substituir Swift? Não. KMP compartilha lógica de negócio, mas a UI no iOS ainda é feita em SwiftUI (ou UIKit). Você precisa de pelo menos conhecimento básico de Swift para trabalhar com KMP em projetos iOS. O que KMP muda é que um dev Kotlin pode entregar mais valor para o time iOS.\nQual é mais fácil de aprender? São muito parecidas em dificuldade. Se você já programa em qualquer linguagem moderna, ambas levam 2-4 semanas para produtividade básica. Se está começando do zero, Kotlin tem mais material em português brasileiro — incluindo nosso guia completo e tutoriais passo a passo.\nDá pra trabalhar com as duas ao mesmo tempo? Sim, e é cada vez mais comum. Times que usam KMP geralmente têm devs que escrevem Kotlin para lógica compartilhada e fazem ajustes em Swift para a camada iOS. É a tendência mais forte no desenvolvimento mobile profissional em 2026.\nKotlin Multiplatform vs SwiftUI: qual o futuro? Não são concorrentes diretos. KMP é sobre compartilhar lógica entre plataformas; SwiftUI é sobre interface no ecossistema Apple. Na prática, times usam KMP para lógica + SwiftUI para UI no iOS + Compose para UI no Android. Veja nosso artigo sobre Compose Multiplatform para entender o cenário completo.\nQuer começar com desenvolvimento mobile em Kotlin? Explore nosso tutorial de primeiro app Android e nosso guia de Jetpack Compose. Também confira o Python Brasil para machine learning e data science, e o Go Brasil para quem quer explorar backend com alta concorrência.\n","permalink":"https://kotlin.dev.br/blog/kotlin-vs-swift-mobile-2026/","summary":"\u003cp\u003eEm 2026, o cenário mobile mudou. Kotlin Multiplatform (KMP) saiu de beta, SwiftUI amadureceu, e a pergunta \u0026ldquo;Kotlin ou Swift?\u0026rdquo; ganhou camadas novas. Se você é dev mobile no Brasil e está escolhendo onde investir sua carreira, este guia prático vai te ajudar a decidir.\u003c/p\u003e\n\u003ch2 id=\"por-que-essa-comparação-importa-em-2026\"\u003ePor que essa comparação importa em 2026\u003c/h2\u003e\n\u003cp\u003eHistoricamente, a resposta era simples: Kotlin para Android, Swift para iOS. Mas com o Kotlin Multiplatform permitindo compartilhar lógica entre Android e iOS, e o SwiftUI facilitando UIs declarativas no ecossistema Apple, as fronteiras ficaram menos claras.\u003c/p\u003e","title":"Kotlin vs Swift: Qual Melhor para Mobile em 2026? | Kotlin Brasil"},{"content":"Você tem um projeto Java rodando em produção — talvez um monolito Spring Boot, talvez microsserviços. O time ouve falar de Kotlin toda semana. Mas migrar vale a pena em 2026? Esse é o guia prático que faltava: sem hype, com dados reais e código lado a lado.\nO cenário em 2026 Java 21+ trouxe records, pattern matching, virtual threads (Project Loom) e sealed classes. Não é mais o Java verboso de 2015. Ao mesmo tempo, Kotlin atingiu a versão 2.1 com o compilador K2 como padrão, trazendo compilação até 2x mais rápida e inferência de tipos ainda melhor.\nA pergunta real não é \u0026ldquo;Kotlin é melhor que Java?\u0026rdquo; — é \u0026ldquo;o custo de migrar compensa para o meu cenário?\u0026rdquo;.\nTabela comparativa: migração em foco Critério Java 21+ Kotlin 2.1 Veredito migração Null safety Optional (não obrigatório) Embutido no sistema de tipos ✅ Kotlin elimina NPEs Verbosidade Records ajudam, mas ainda verboso Data classes, extension functions ✅ Kotlin 30-40% menos código Coroutines vs Threads Virtual Threads (Loom) Coroutines + Flow 🟡 Ambos excelentes Spring Boot Suporte nativo completo Suporte oficial desde Spring 5 🟡 Empate Curva de aprendizado Time já conhece 2-4 semanas para devs Java ✅ Transição suave Interoperabilidade N/A 100% compatível com Java ✅ Migração gradual possível Tooling IntelliJ, Eclipse, VS Code IntelliJ (criadora do Kotlin) ✅ Kotlin leva vantagem no IntelliJ Ecossistema de libs O maior da JVM Usa todas as libs Java + próprias 🟡 Empate Onde Kotlin brilha na migração 1. Null safety elimina uma classe inteira de bugs Em Java, NullPointerException ainda é o erro mais comum em produção. O Optional ajuda, mas ninguém garante que todo o código usa:\n// Java - NPE esperando pra acontecer public String getNomeCliente(Pedido pedido) { return pedido.getCliente().getNome().toUpperCase(); // Se cliente for null? 💥 NPE em produção } // Kotlin - o compilador te protege fun getNomeCliente(pedido: Pedido): String { return pedido.cliente?.nome?.uppercase() ?: \u0026#34;Cliente não informado\u0026#34; // Null safety embutido, sem surpresas } Empresas que migraram reportam redução de 30-50% nos bugs de produção relacionados a null. Se seu projeto sofre com NPEs frequentes, esse motivo sozinho pode justificar a migração.\n2. Coroutines simplificam código assíncrono Com o Project Loom, Java ganhou virtual threads — excelentes para I/O. Mas Kotlin Coroutines oferecem um modelo estruturado que vai além:\n// Kotlin - structured concurrency suspend fun processarPedido(id: Long): Resultado { return coroutineScope { val cliente = async { buscarCliente(id) } val estoque = async { verificarEstoque(id) } val pagamento = async { validarPagamento(id) } // Três chamadas em paralelo, código legível Resultado(cliente.await(), estoque.await(), pagamento.await()) } // Se qualquer um falhar, todos são cancelados automaticamente } Para comparar com Java usando virtual threads:\n// Java 21 - Virtual Threads try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { Future\u0026lt;Cliente\u0026gt; cliente = executor.submit(() -\u0026gt; buscarCliente(id)); Future\u0026lt;Estoque\u0026gt; estoque = executor.submit(() -\u0026gt; verificarEstoque(id)); Future\u0026lt;Pagamento\u0026gt; pagamento = executor.submit(() -\u0026gt; validarPagamento(id)); return new Resultado(cliente.get(), estoque.get(), pagamento.get()); } Ambos funcionam, mas Coroutines oferecem cancelamento estruturado, Flow para streams reativos e integração profunda com o ecossistema Android e Ktor.\n3. Extension functions eliminam classes utilitárias Chega de StringUtils, DateUtils, CollectionUtils:\n// Kotlin - extensão direto no tipo fun String.toSlug(): String = this.lowercase() .replace(Regex(\u0026#34;[^a-z0-9\\\\s-]\u0026#34;), \u0026#34;\u0026#34;) .replace(Regex(\u0026#34;\\\\s+\u0026#34;), \u0026#34;-\u0026#34;) .trim(\u0026#39;-\u0026#39;) // Uso natural val url = \u0026#34;Kotlin vs Java: Vale a Pena?\u0026#34;.toSlug() // \u0026#34;kotlin-vs-java-vale-a-pena\u0026#34; Isso não é só açúcar sintático — muda como o time pensa sobre código. Menos indireção, mais legibilidade. Veja mais em nosso tutorial de extension functions.\nOnde Java segue forte Virtual Threads são game-changer O Project Loom nivelou o jogo para workloads de I/O intensivo. Se seu projeto é um backend CRUD com muitas chamadas a banco e APIs externas, Java 21+ com virtual threads performa tão bem quanto Kotlin Coroutines.\nEcossistema corporativo maduro Grandes empresas brasileiras como bancos e seguradoras têm bases de código Java enormes. Frameworks como Spring Boot, Quarkus e Micronaut têm suporte Java como cidadão de primeira classe. Se sua empresa já tem padrões internos Java estabelecidos e governança rígida, migrar pode ter custo político alto.\nProfissionais disponíveis O mercado brasileiro tem significativamente mais desenvolvedores Java do que Kotlin. Isso importa na hora de contratar. Confira nosso artigo sobre vagas Kotlin no Brasil e salários no mercado para ter uma noção clara.\nEstratégia de migração gradual A melhor parte de migrar para Kotlin? Você não precisa reescrever tudo. A interoperabilidade é 100% — Java chama Kotlin e Kotlin chama Java sem fricção.\nPasso 1: Novos arquivos em Kotlin Configure o Gradle para suportar ambas as linguagens e escreva todo código novo em Kotlin.\nPasso 2: Converta arquivos críticos Use o conversor automático do IntelliJ (Ctrl+Alt+Shift+K) e depois refatore manualmente para Kotlin idiomático.\nPasso 3: Migre testes primeiro Testes são o lugar mais seguro pra começar. MockK e Kotest tornam testes em Kotlin muito mais expressivos.\nPasso 4: Adote Kotlin DSL no Gradle Troque build.gradle por build.gradle.kts. Veja nosso tutorial de Gradle Kotlin DSL para um guia passo a passo.\nMercado de trabalho no Brasil O mercado brasileiro de Kotlin cresce consistentemente. Segundo dados que compilamos:\nVagas backend Kotlin cresceram 45% entre 2024 e 2026 no Brasil Salário médio de dev Kotlin sênior: R$ 18.000 - R$ 28.000/mês (remoto) Salário médio de dev Java sênior: R$ 14.000 - R$ 22.000/mês (remoto) Empresas como iFood, Nubank, PicPay e BTG Pactual já usam Kotlin em produção Kotlin Multiplatform está abrindo vagas que antes não existiam O diferencial salarial de 20-30% é real e vem do fato de que a demanda por Kotlin cresce mais rápido que a oferta de profissionais qualificados. Confira nosso roadmap de carreira backend Kotlin para planejar sua transição.\nSe você é dev Java pensando em migrar pessoalmente, leia nosso guia de transição Java para Kotlin — cobre tudo que você precisa saber.\nConclusão — Vale a pena migrar? Sim, na maioria dos casos. Especialmente se:\n✅ Seu time sofre com NPEs e bugs de null ✅ Você quer código mais conciso e legível ✅ O projeto usa Spring Boot (suporte Kotlin é excelente) ✅ Você está começando microsserviços novos ✅ O time demonstra interesse em aprender Talvez não, se:\n⚠️ O projeto é legado com milhões de linhas Java e sem budget pra refatoração ⚠️ A empresa tem governança rígida que não permite mudanças de linguagem ⚠️ Todo o time é sênior em Java e não há interesse em mudar A migração gradual é o caminho — nunca reescreva tudo de uma vez. Comece por novos módulos, migre testes, e deixe o time ganhar confiança naturalmente.\nFAQ — Perguntas frequentes Kotlin vai substituir Java? Não. Kotlin e Java coexistem na JVM e são 100% interoperáveis. Java continua evoluindo (records, pattern matching, Loom) e tem uma base instalada gigantesca. O cenário mais realista é Kotlin dominando novos projetos enquanto Java permanece forte em manutenção de sistemas existentes.\nPosso misturar Kotlin e Java no mesmo projeto? Sim, sem restrições. Kotlin foi projetado especificamente para isso. Você pode ter arquivos .java e .kt no mesmo módulo, chamando um ao outro livremente. É assim que a migração gradual funciona na prática.\nEmpresas no Brasil usam Kotlin em produção? Sim, e cada vez mais. iFood, Nubank, PicPay, BTG Pactual, Globo, Magazine Luiza e dezenas de outras empresas brasileiras usam Kotlin em produção — tanto para Android quanto para backend. Veja nossa lista completa de empresas.\nQuanto tempo leva pra um dev Java aprender Kotlin? Um desenvolvedor Java experiente consegue ser produtivo em Kotlin em 2-4 semanas. A sintaxe é familiar, os conceitos JVM são os mesmos, e o IntelliJ converte código automaticamente. O desafio maior é aprender a pensar de forma idiomática — usar sealed classes, extension functions e coroutines de forma natural.\nE para quem está começando do zero: Java ou Kotlin? Se você está começando agora e quer desenvolver para Android, vá direto de Kotlin. O Google recomenda, a documentação oficial é Kotlin-first, e o Jetpack Compose só funciona com Kotlin. Para backend, ambas são boas opções, mas Kotlin te dará uma experiência mais moderna desde o início. Comece com nosso guia completo de Kotlin.\nEstá pensando em migrar de Java para Kotlin? Explore nossos tutoriais práticos e comece hoje mesmo. Para quem trabalha com outras linguagens, confira também o Go Brasil, o Rust Brasil e o Python Brasil.\n","permalink":"https://kotlin.dev.br/blog/kotlin-vs-java-migrar-vale-pena-2026/","summary":"\u003cp\u003eVocê tem um projeto Java rodando em produção — talvez um monolito Spring Boot, talvez microsserviços. O time ouve falar de Kotlin toda semana. Mas \u003cstrong\u003emigrar vale a pena em 2026?\u003c/strong\u003e Esse é o guia prático que faltava: sem hype, com dados reais e código lado a lado.\u003c/p\u003e\n\u003ch2 id=\"o-cenário-em-2026\"\u003eO cenário em 2026\u003c/h2\u003e\n\u003cp\u003eJava 21+ trouxe records, pattern matching, virtual threads (Project Loom) e sealed classes. Não é mais o Java verboso de 2015. Ao mesmo tempo, Kotlin atingiu a versão 2.1 com o compilador K2 como padrão, trazendo compilação até 2x mais rápida e inferência de tipos ainda melhor.\u003c/p\u003e","title":"Kotlin vs Java: Vale a Pena Migrar em 2026? | Kotlin Brasil"},{"content":"Compartilhar lógica de negócio entre plataformas com Kotlin Multiplatform já era realidade. Mas compartilhar a interface gráfica sempre foi o maior desafio. O Compose Multiplatform (CMP) da JetBrains muda esse cenário ao permitir que você escreva UI em Kotlin uma vez e rode no Android, iOS, Desktop e Web. Em 2026, com a estabilização do suporte a iOS e melhorias em todas as frentes, CMP se tornou uma alternativa séria para projetos multiplataforma.\nO que é Compose Multiplatform? Compose Multiplatform é um framework de UI declarativo da JetBrains construído sobre o Jetpack Compose do Google. A ideia é simples: se o Jetpack Compose funciona perfeitamente para Android, por que não levar o mesmo modelo para outras plataformas?\nCMP usa o mecanismo de renderização Skia (a mesma engine do Chrome e do Flutter) para desenhar a UI de forma consistente em todas as plataformas. Isso significa que seus Composables rodam nativamente em:\nPlataforma Status em 2026 Renderização Android Estável (produção) Nativo via Jetpack Compose iOS Beta avançado Skia + UIKit integration Desktop (JVM) Estável (produção) Skia via JVM Web (Wasm) Alpha/Experimental Skia via WebAssembly Se você já trabalhou com Compose para Desktop, CMP leva essa experiência ao próximo nível ao unificar todos os targets.\nConfigurando um Projeto CMP A maneira mais rápida de começar é com o Kotlin Multiplatform Wizard da JetBrains (kmp.jetbrains.com). Mas vamos entender a estrutura manualmente.\nEstrutura do Projeto meu-app-cmp/ ├── composeApp/ │ ├── src/ │ │ ├── commonMain/ # UI e lógica compartilhada │ │ ├── androidMain/ # Código Android específico │ │ ├── iosMain/ # Código iOS específico │ │ └── desktopMain/ # Código Desktop específico │ └── build.gradle.kts ├── iosApp/ # Projeto Xcode wrapper ├── build.gradle.kts └── settings.gradle.kts Configuração do Gradle // composeApp/build.gradle.kts plugins { kotlin(\u0026#34;multiplatform\u0026#34;) id(\u0026#34;org.jetbrains.compose\u0026#34;) id(\u0026#34;org.jetbrains.kotlin.plugin.compose\u0026#34;) } kotlin { androidTarget() jvm(\u0026#34;desktop\u0026#34;) listOf( iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { target -\u0026gt; target.binaries.framework { baseName = \u0026#34;ComposeApp\u0026#34; isStatic = true } } sourceSets { commonMain.dependencies { implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material3) implementation(compose.ui) implementation(compose.components.resources) } androidMain.dependencies { implementation(compose.preview) implementation(\u0026#34;androidx.activity:activity-compose:1.9.0\u0026#34;) } val desktopMain by getting { dependencies { implementation(compose.desktop.currentOs) } } } } Compartilhando UI entre Plataformas O coração do CMP é o source set commonMain. Todo código colocado aqui roda em todas as plataformas. Vamos criar uma tela de perfil de usuário compartilhada:\n// commonMain/kotlin/ui/PerfilScreen.kt @Composable fun PerfilScreen(usuario: Usuario) { Column( modifier = Modifier .fillMaxSize() .padding(24.dp), horizontalAlignment = Alignment.CenterHorizontally ) { // Avatar circular Box( modifier = Modifier .size(120.dp) .clip(CircleShape) .background(MaterialTheme.colorScheme.primaryContainer), contentAlignment = Alignment.Center ) { Text( text = usuario.nome.first().toString(), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimaryContainer ) } Spacer(modifier = Modifier.height(16.dp)) Text( text = usuario.nome, style = MaterialTheme.typography.headlineMedium ) Text( text = usuario.email, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurfaceVariant ) Spacer(modifier = Modifier.height(32.dp)) // Lista de informações InfoCard(\u0026#34;Cargo\u0026#34;, usuario.cargo) InfoCard(\u0026#34;Localização\u0026#34;, usuario.cidade) InfoCard(\u0026#34;Membro desde\u0026#34;, usuario.membroDesde) } } @Composable fun InfoCard(label: String, valor: String) { Card( modifier = Modifier .fillMaxWidth() .padding(vertical = 4.dp) ) { Row( modifier = Modifier.padding(16.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { Text( text = label, style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.onSurfaceVariant ) Text( text = valor, style = MaterialTheme.typography.bodyLarge ) } } } Esse código roda exatamente igual no Android, iOS e Desktop. Sem adaptações, sem #ifdef, sem código duplicado.\nCódigo Específico por Plataforma com expect/actual Nem tudo pode ser compartilhado. Para funcionalidades específicas de cada plataforma, o KMP oferece o mecanismo expect/actual:\n// commonMain — declaração expect expect fun compartilharTexto(texto: String) expect fun obterVersaoApp(): String // androidMain — implementação actual actual fun compartilharTexto(texto: String) { val intent = Intent(Intent.ACTION_SEND).apply { type = \u0026#34;text/plain\u0026#34; putExtra(Intent.EXTRA_TEXT, texto) } context.startActivity(Intent.createChooser(intent, \u0026#34;Compartilhar\u0026#34;)) } actual fun obterVersaoApp(): String { return BuildConfig.VERSION_NAME } // iosMain — implementação actual actual fun compartilharTexto(texto: String) { val activityController = UIActivityViewController( activityItems = listOf(texto), applicationActivities = null ) UIApplication.sharedApplication.keyWindow?.rootViewController ?.presentViewController(activityController, true, null) } actual fun obterVersaoApp(): String { return NSBundle.mainBundle.infoDictionary ?.get(\u0026#34;CFBundleShortVersionString\u0026#34;) as? String ?: \u0026#34;1.0\u0026#34; } O compilador garante que toda declaração expect tenha sua contrapartida actual em cada target. Sem actual, o build falha — segurança em tempo de compilação.\nNavegação em Compose Multiplatform Navegação é um dos pontos que mais evoluiu em 2026. A biblioteca oficial Compose Navigation agora suporta KMP nativamente:\n// commonMain @Composable fun AppNavigation() { val navController = rememberNavController() NavHost( navController = navController, startDestination = \u0026#34;home\u0026#34; ) { composable(\u0026#34;home\u0026#34;) { HomeScreen( onPerfilClick = { navController.navigate(\u0026#34;perfil/$it\u0026#34;) }, onConfigClick = { navController.navigate(\u0026#34;configuracoes\u0026#34;) } ) } composable(\u0026#34;perfil/{userId}\u0026#34;) { backStackEntry -\u0026gt; val userId = backStackEntry.arguments?.getString(\u0026#34;userId\u0026#34;) ?: return@composable PerfilScreen( userId = userId, onVoltar = { navController.popBackStack() } ) } composable(\u0026#34;configuracoes\u0026#34;) { ConfiguracoesScreen( onVoltar = { navController.popBackStack() } ) } } } Alternativas populares para navegação multiplataforma incluem:\nVoyager — API simples e intuitiva, inspirada no Jetpack Navigation Decompose — arquitetura baseada em componentes, boa para apps complexos Appyx — navegação com animações avançadas Gerenciamento de Estado Para gerenciamento de estado, CMP funciona com as mesmas ferramentas do Compose:\n// ViewModel compartilhado usando kotlinx-coroutines e Flow class PerfilViewModel( private val repository: UsuarioRepository ) { private val _uiState = MutableStateFlow\u0026lt;PerfilUiState\u0026gt;(PerfilUiState.Carregando) val uiState: StateFlow\u0026lt;PerfilUiState\u0026gt; = _uiState.asStateFlow() fun carregarPerfil(userId: String) { CoroutineScope(Dispatchers.Default).launch { _uiState.value = PerfilUiState.Carregando try { val usuario = repository.buscarUsuario(userId) _uiState.value = PerfilUiState.Sucesso(usuario) } catch (e: Exception) { _uiState.value = PerfilUiState.Erro(e.message ?: \u0026#34;Erro desconhecido\u0026#34;) } } } } sealed class PerfilUiState { data object Carregando : PerfilUiState() data class Sucesso(val usuario: Usuario) : PerfilUiState() data class Erro(val mensagem: String) : PerfilUiState() } Se você já trabalha com Coroutines e Flow no Android, a transição para CMP é natural. Confira nosso guia completo de Coroutines para dominar esses conceitos.\nLimitações e Considerações CMP amadureceu muito, mas ainda tem limitações que você precisa considerar:\niOS ainda em Beta O suporte a iOS avançou significativamente, mas ainda é beta. Widgets de sistema, deep links avançados e algumas APIs do UIKit exigem código nativo. Para apps em produção no iOS, teste extensivamente.\nPerformance no iOS A renderização via Skia no iOS tem overhead comparado a SwiftUI nativo. Para a maioria dos apps, a diferença é imperceptível. Para apps com animações pesadas ou listas muito longas, monitore o desempenho.\nTamanho do binário Apps CMP tendem a ter binários maiores do que apps nativos puros, pois incluem o runtime do Skia. No Android, o impacto é menor (~2-3 MB extra). No iOS, pode chegar a ~10-15 MB adicionais.\nEcossistema de bibliotecas Nem todas as bibliotecas do Jetpack Compose estão disponíveis para KMP. Antes de adotar CMP, verifique se suas dependências-chave suportam multiplataforma.\nCMP vs Flutter vs React Native Uma comparação inevitável. Cada framework tem seus pontos fortes:\nAspecto Compose Multiplatform Flutter React Native Linguagem Kotlin Dart JavaScript/TypeScript Renderização Skia Skia (Impeller) Componentes nativos Código compartilhado UI + Lógica UI + Lógica UI + Lógica Integração nativa Excelente (KMP) Boa (Platform Channels) Boa (Native Modules) Curva de aprendizado Baixa (se sabe Kotlin) Média Baixa (se sabe JS) Maturidade Em crescimento Madura Madura Se sua equipe já domina Kotlin e tem um app Android com Jetpack Compose, CMP é a escolha mais natural — o código existente pode ser reaproveitado. Confira nossa comparação detalhada entre KMP e Flutter e entre KMP e React Native.\nPara quem vem de outras linguagens, vale conhecer como cada ecossistema resolve o desafio de multiplataforma. Go também tem propostas de UI multiplataforma como Gio, embora com foco diferente. Já Python investe em frameworks como Kivy e BeeWare para o mesmo objetivo.\nExemplo Completo: App de Tarefas Para consolidar, veja uma tela funcional de lista de tarefas compartilhada:\n@Composable fun TarefasScreen(viewModel: TarefasViewModel) { val tarefas by viewModel.tarefas.collectAsState() var novaTarefa by remember { mutableStateOf(\u0026#34;\u0026#34;) } Scaffold( topBar = { TopAppBar(title = { Text(\u0026#34;Minhas Tarefas\u0026#34;) }) } ) { padding -\u0026gt; Column( modifier = Modifier .fillMaxSize() .padding(padding) .padding(16.dp) ) { // Campo de nova tarefa Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { OutlinedTextField( value = novaTarefa, onValueChange = { novaTarefa = it }, modifier = Modifier.weight(1f), placeholder = { Text(\u0026#34;Nova tarefa...\u0026#34;) }, singleLine = true ) Spacer(modifier = Modifier.width(8.dp)) IconButton( onClick = { if (novaTarefa.isNotBlank()) { viewModel.adicionar(novaTarefa) novaTarefa = \u0026#34;\u0026#34; } } ) { Icon(Icons.Default.Add, \u0026#34;Adicionar\u0026#34;) } } Spacer(modifier = Modifier.height(16.dp)) // Lista de tarefas LazyColumn { items(tarefas) { tarefa -\u0026gt; TarefaItem( tarefa = tarefa, onToggle = { viewModel.alternarConclusao(tarefa.id) }, onRemover = { viewModel.remover(tarefa.id) } ) } } } } } Conclusão Compose Multiplatform em 2026 é uma tecnologia madura o suficiente para projetos reais — especialmente se sua equipe já trabalha com Kotlin e Jetpack Compose. O compartilhamento de UI entre Android, iOS e Desktop reduz significativamente o esforço de desenvolvimento e manutenção.\nPara começar, recomendo explorar nosso guia de Kotlin Multiplatform Mobile e o artigo sobre o futuro do KMP. Se você quer entender a base do Compose, confira o guia de Jetpack Compose.\nO ecossistema Kotlin continua evoluindo — e o CMP é uma das peças mais empolgantes desse quebra-cabeça.\nSe você busca performance nativa sem garbage collector para componentes críticos do seu app multiplataforma, vale explorar como Rust aborda interoperabilidade com mobile e WebAssembly.\n","permalink":"https://kotlin.dev.br/blog/kotlin-compose-multiplatform-ui-2026/","summary":"\u003cp\u003eCompartilhar lógica de negócio entre plataformas com \u003ca href=\"/blog/kotlin-multiplatform/\"\u003eKotlin Multiplatform\u003c/a\u003e já era realidade. Mas compartilhar a \u003cstrong\u003einterface gráfica\u003c/strong\u003e sempre foi o maior desafio. O \u003cstrong\u003eCompose Multiplatform (CMP)\u003c/strong\u003e da JetBrains muda esse cenário ao permitir que você escreva UI em Kotlin uma vez e rode no Android, iOS, Desktop e Web. Em 2026, com a estabilização do suporte a iOS e melhorias em todas as frentes, CMP se tornou uma alternativa séria para projetos multiplataforma.\u003c/p\u003e","title":"Compose Multiplatform: UI Compartilhada em 2026 | Kotlin Brasil"},{"content":"O Kotlin 2.1 é um marco importante para a linguagem. Com o compilador K2 finalmente como padrão, novos recursos de sintaxe e melhorias significativas em Kotlin/JS e Kotlin/Wasm, esta versão consolida o Kotlin como uma das linguagens mais modernas e produtivas do ecossistema JVM — e além dele. Neste artigo, vamos explorar cada novidade do Kotlin 2.1 com exemplos práticos de código.\nCompilador K2 como Padrão A mudança mais significativa do Kotlin 2.1 é que o compilador K2 agora é o padrão em todos os targets. Se você acompanhou a evolução do Kotlin em 2026, sabe que o K2 já vinha sendo testado. Agora ele é oficial.\nO que muda na prática? O K2 traz ganhos reais que você vai sentir no dia a dia:\nCompilação até 2x mais rápida em projetos grandes Inferência de tipos mais inteligente — menos anotações explícitas Melhor resolução de overloads — menos ambiguidades Smart casts mais poderosos — o compilador entende mais contextos // Inferência de tipos melhorada no K2 val mapa = buildMap { put(\u0026#34;usuarios\u0026#34;, listOf( mapOf(\u0026#34;nome\u0026#34; to \u0026#34;Ana\u0026#34;, \u0026#34;idade\u0026#34; to 28), mapOf(\u0026#34;nome\u0026#34; to \u0026#34;Carlos\u0026#34;, \u0026#34;idade\u0026#34; to 35) )) } // K2 infere corretamente: Map\u0026lt;String, List\u0026lt;Map\u0026lt;String, Any\u0026gt;\u0026gt;\u0026gt; // Smart casts em cenários mais complexos fun processar(valor: Any) { if (valor is String \u0026amp;\u0026amp; valor.length \u0026gt; 5) { // K2 mantém o smart cast em expressões encadeadas println(valor.uppercase().take(3)) } } Migrando para o K2 Se seu projeto ainda usa o compilador legado, a migração é simples. No gradle.properties:\n# Remova esta linha se existir — K2 agora é o padrão # kotlin.useK2=true # Se precisar voltar temporariamente ao compilador legado: # kotlin.useK2=false A maioria dos projetos não precisa de nenhuma alteração. Se você usa KSP para geração de código, certifique-se de estar na versão mais recente, pois KSP já tem suporte nativo ao K2.\nGuard Conditions em Expressões when Uma das novidades mais pedidas pela comunidade: guard conditions em expressões when. Agora é possível adicionar condições extras a cada branch usando a palavra-chave if, sem precisar de when aninhados ou variáveis temporárias.\nsealed class Resultado { data class Sucesso(val dados: List\u0026lt;String\u0026gt;) : Resultado() data class Erro(val codigo: Int, val mensagem: String) : Resultado() data object Carregando : Resultado() } fun tratarResultado(resultado: Resultado) { when (resultado) { is Resultado.Sucesso if resultado.dados.isNotEmpty() -\u0026gt; { println(\u0026#34;Recebidos ${resultado.dados.size} itens\u0026#34;) resultado.dados.forEach { println(\u0026#34; - $it\u0026#34;) } } is Resultado.Sucesso -\u0026gt; { println(\u0026#34;Sucesso, mas sem dados\u0026#34;) } is Resultado.Erro if resultado.codigo in 400..499 -\u0026gt; { println(\u0026#34;Erro do cliente: ${resultado.mensagem}\u0026#34;) } is Resultado.Erro if resultado.codigo in 500..599 -\u0026gt; { println(\u0026#34;Erro do servidor: ${resultado.mensagem}\u0026#34;) } is Resultado.Erro -\u0026gt; { println(\u0026#34;Erro desconhecido: ${resultado.codigo}\u0026#34;) } Resultado.Carregando -\u0026gt; { println(\u0026#34;Aguardando...\u0026#34;) } } } Isso é particularmente útil com sealed classes — um recurso central do Kotlin para modelagem de domínio. Antes, você precisaria de blocos if dentro de cada branch ou expressões when aninhadas. Agora, guard conditions tornam o código mais limpo e expressivo.\nQuando usar guard conditions? Validação de estado: filtrar combinações específicas de propriedades Tratamento de erros: diferenciar tipos de erro por código ou contexto Pattern matching: combinar checagem de tipo com condições sobre o valor Se você vem de linguagens como Rust ou Scala, vai reconhecer o conceito. O Kotlin finalmente tem pattern matching mais expressivo, semelhante ao que Rust oferece com seus match guards.\nNon-local break e continue em Inline Lambdas Outra novidade aguardada: agora é possível usar break e continue dentro de lambdas passadas para funções inline. Isso resolve uma frustração antiga de quem trabalha com higher-order functions.\nfun processarUsuarios(usuarios: List\u0026lt;Usuario\u0026gt;) { for (usuario in usuarios) { usuario.enderecos.forEach { endereco -\u0026gt; if (endereco.cep.isBlank()) { continue // Agora funciona! Pula para o próximo endereço } if (endereco.pais != \u0026#34;BR\u0026#34;) { break // Sai do forEach completamente } enviarNotificacao(usuario, endereco) } } } Antes do Kotlin 2.1, break e continue dentro de lambdas inline geravam erro de compilação. A solução era usar return@forEach (que funciona como continue) ou criar variáveis de controle. Agora, o código fica mais natural e legível.\nAtenção com return Lembre-se: em lambdas inline, return sem label já faz return da função enclosing. Com break e continue, o comportamento agora é completo:\ninline fun \u0026lt;T\u0026gt; Iterable\u0026lt;T\u0026gt;.processarCada(acao: (T) -\u0026gt; Unit) { for (item in this) { acao(item) // break/continue dentro da lambda afetam este for } } fun exemplo() { listOf(1, 2, 3, 4, 5).processarCada { numero -\u0026gt; if (numero == 3) continue // Pula o 3 if (numero == 5) break // Para no 5 println(numero) // Imprime: 1, 2, 4 } } Multi-dollar String Interpolation String templates ficaram mais poderosas com a interpolação multi-dollar. Agora você pode definir quantos $ são necessários para acionar a interpolação, facilitando o trabalho com templates que contêm $ literal.\n// Antes: escapar $ era necessário em regex, templates, etc. val regex = \u0026#34;\u0026#34;\u0026#34;\\${\u0026#39;$\u0026#39;}\\{(\\w+)\\}\u0026#34;\u0026#34;\u0026#34; // Agora com multi-dollar ($$): um único $ é literal val regex = $$\u0026#34;\u0026#34;\u0026#34;\\$\\{(\\w+)\\}\u0026#34;\u0026#34;\u0026#34; // Interpolação com $$: usa $$ para variáveis val nome = \u0026#34;Kotlin\u0026#34; val template = $$\u0026#34;\u0026#34;\u0026#34; O valor de $$nome é interpolado. Mas $variavel é literal — não é interpolado. Útil para templates de código ou regex complexas. \u0026#34;\u0026#34;\u0026#34; Esse recurso é especialmente útil quando você trabalha com:\nTemplates de código — geradores que produzem código com $ Expressões regulares — regex que usam $ para âncoras Templates de configuração — arquivos YAML/JSON com variáveis ${} DSLs — se você cria DSLs em Kotlin, multi-dollar simplifica templates Melhorias em Kotlin/JS e Kotlin/Wasm O Kotlin 2.1 trouxe avanços significativos para compilação JavaScript e WebAssembly:\nKotlin/JS Geração de código ES2015+ otimizada — módulos ES menores e mais eficientes Melhor interop com TypeScript — declarações .d.ts mais precisas Tree shaking aprimorado — dead code elimination mais agressivo Kotlin/Wasm Performance de runtime melhorada — execução até 30% mais rápida em benchmarks Garbage collector otimizado — menos pausas e menor uso de memória Melhor interop com JavaScript — chamadas entre Wasm e JS mais eficientes // Código KMP que compila para JS e Wasm @OptIn(ExperimentalWasmDsl::class) kotlin { js(IR) { browser() nodejs() } wasmJs { browser() } sourceSets { commonMain.dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0\u0026#34;) } } } Se você trabalha com Kotlin Multiplatform, essas melhorias significam que targets web agora são viáveis para produção. O futuro do KMP no browser é cada vez mais real.\nGuia de Migração: De Kotlin 1.x para 2.1 Se seu projeto ainda está no Kotlin 1.9.x, a migração para 2.1 segue estes passos:\n1. Atualize o Gradle Plugin // build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.1.0\u0026#34; // ou para multiplatform: kotlin(\u0026#34;multiplatform\u0026#34;) version \u0026#34;2.1.0\u0026#34; } 2. Verifique Deprecações O compilador K2 é mais rigoroso em alguns cenários. Execute o build e trate os warnings:\n./gradlew build --warning-mode all 3. Atualize Dependências Certifique-se de que suas dependências suportam Kotlin 2.1:\n// Versões compatíveis recomendadas dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-core:3.0.0\u0026#34;) } 4. Teste Extensivamente O K2 pode gerar código ligeiramente diferente em edge cases. Se você tem testes unitários bem escritos, eles vão capturar qualquer regressão.\nImpacto no Ecossistema O Kotlin 2.1 não é apenas sobre a linguagem — ele afeta todo o ecossistema:\nAndroid: compilações mais rápidas com K2 e melhor suporte para Jetpack Compose Backend: frameworks como Ktor e Spring Boot já suportam Kotlin 2.1 Multiplatform: Compose Multiplatform se beneficia diretamente das melhorias Para quem trabalha com backend, vale a pena comparar como outras linguagens modernas evoluem seus compiladores. Go, por exemplo, também investe pesado em performance de compilação, enquanto Rust prioriza garantias em tempo de compilação — cada abordagem com seus trade-offs.\nConclusão O Kotlin 2.1 é uma release que consolida a maturidade da linguagem. O compilador K2 como padrão traz ganhos de performance e DX. Guard conditions e non-local break/continue tornam o código mais expressivo. Multi-dollar interpolation resolve dores de cabeça com templates. E as melhorias em JS/Wasm abrem novas portas para o KMP.\nSe você está começando com Kotlin, confira nosso guia completo. Se já trabalha com a linguagem, atualize seus projetos — as melhorias valem cada minuto de migração.\nPara quem também trabalha com ciência de dados ou automação, vale conferir como Python evolui seu ecossistema de tipagem e performance — as linguagens modernas convergem em muitos aspectos.\n","permalink":"https://kotlin.dev.br/blog/kotlin-21-novidades-2026/","summary":"\u003cp\u003eO Kotlin 2.1 é um marco importante para a linguagem. Com o compilador K2 finalmente como padrão, novos recursos de sintaxe e melhorias significativas em Kotlin/JS e Kotlin/Wasm, esta versão consolida o Kotlin como uma das linguagens mais modernas e produtivas do ecossistema JVM — e além dele. Neste artigo, vamos explorar cada novidade do Kotlin 2.1 com exemplos práticos de código.\u003c/p\u003e\n\u003ch2 id=\"compilador-k2-como-padrão\"\u003eCompilador K2 como Padrão\u003c/h2\u003e\n\u003cp\u003eA mudança mais significativa do Kotlin 2.1 é que o \u003cstrong\u003ecompilador K2\u003c/strong\u003e agora é o padrão em todos os targets. Se você acompanhou a \u003ca href=\"/blog/kotlin-2026-novidades/\"\u003eevolução do Kotlin em 2026\u003c/a\u003e, sabe que o K2 já vinha sendo testado. Agora ele é oficial.\u003c/p\u003e","title":"Kotlin 2.1: Novidades e Melhorias em 2026 | Kotlin Brasil"},{"content":"Quantas vezes você já passou um String onde deveria ser um ID, ou confundiu metros com quilômetros porque ambos eram Double? Esses bugs silenciosos são comuns em projetos Kotlin — e as value classes existem justamente para eliminá-los. Neste guia, vamos explorar tudo sobre value classes: desde a sintaxe básica até padrões avançados de modelagem de domínio, sempre com foco em performance e type safety.\nO que São Value Classes? Value classes (anteriormente chamadas de inline classes) são um recurso do Kotlin que permite criar tipos wrapper sem custo de alocação em runtime. O compilador substitui a value class pelo valor interno sempre que possível, eliminando a criação de objetos no heap.\n@JvmInline value class UserId(val value: Long) @JvmInline value class Email(val value: String) fun findUser(id: UserId): User? { /* ... */ } // Em tempo de compilação: tipagem forte // Em runtime: é apenas um Long (sem boxing) val id = UserId(42) findUser(id) // ✅ Compila findUser(UserId(99)) // ✅ Compila // findUser(42) // ❌ Não compila — type safety! A anotação @JvmInline é obrigatória desde o Kotlin 1.5 e indica ao compilador que esta classe deve ser \u0026ldquo;inlineada\u0026rdquo; — ou seja, o wrapper é removido no bytecode gerado.\nEvolução: De Inline Classes para Value Classes As value classes são a evolução das inline classes experimentais do Kotlin 1.2. A mudança de nome reflete a intenção do time do Kotlin de, no futuro, suportar value classes com múltiplas propriedades (Valhalla Project da JVM). Por enquanto, a restrição é:\nExatamente uma propriedade no construtor primário A propriedade deve ser val (imutável) Anotação @JvmInline obrigatória para a JVM // ✅ Válido @JvmInline value class ProductName(val name: String) // ❌ Inválido — duas propriedades // @JvmInline // value class Money(val amount: Double, val currency: String) Casos de Uso Práticos 1. Typed IDs (IDs Tipados) O caso de uso mais clássico. Em vez de passar Long ou String para tudo, cada entidade tem seu próprio tipo de ID:\n@JvmInline value class UserId(val value: Long) @JvmInline value class OrderId(val value: Long) @JvmInline value class ProductId(val value: Long) // Impossível confundir um ID com outro fun getOrder(orderId: OrderId): Order? { /* ... */ } fun getUser(userId: UserId): User? { /* ... */ } val orderId = OrderId(100) val userId = UserId(200) getOrder(orderId) // ✅ // getOrder(userId) // ❌ Type mismatch — erro em tempo de compilação! Esse padrão é especialmente poderoso em projetos com arquitetura limpa onde a camada de domínio precisa de tipos expressivos.\n2. Unidades de Medida Evite confusões entre unidades usando value classes:\n@JvmInline value class Meters(val value: Double) { fun toKilometers(): Kilometers = Kilometers(value / 1000.0) operator fun plus(other: Meters): Meters = Meters(value + other.value) operator fun compareTo(other: Meters): Int = value.compareTo(other.value) } @JvmInline value class Kilometers(val value: Double) { fun toMeters(): Meters = Meters(value * 1000.0) } @JvmInline value class Celsius(val value: Double) { fun toFahrenheit(): Fahrenheit = Fahrenheit(value * 9.0 / 5.0 + 32.0) } @JvmInline value class Fahrenheit(val value: Double) // Uso val distance = Meters(1500.0) val km = distance.toKilometers() println(\u0026#34;${distance.value}m = ${km.value}km\u0026#34;) // 1500.0m = 1.5km 3. Validação no Construtor Combine value classes com blocos init para garantir invariantes:\n@JvmInline value class Email(val value: String) { init { require(value.contains(\u0026#34;@\u0026#34;) \u0026amp;\u0026amp; value.contains(\u0026#34;.\u0026#34;)) { \u0026#34;Email inválido: $value\u0026#34; } } } @JvmInline value class Percentage(val value: Double) { init { require(value in 0.0..100.0) { \u0026#34;Porcentagem deve estar entre 0 e 100: $value\u0026#34; } } } @JvmInline value class NonBlankString(val value: String) { init { require(value.isNotBlank()) { \u0026#34;String não pode ser vazia\u0026#34; } } } // Falha rápido — melhor que descobrir o bug em produção val email = Email(\u0026#34;dev@kotlin.dev.br\u0026#34;) // ✅ // val invalid = Email(\u0026#34;sem-arroba\u0026#34;) // ❌ IllegalArgumentException 4. Wrapper para APIs Externas Torne APIs de terceiros mais seguras com tipagem:\n@JvmInline value class JsonString(val raw: String) @JvmInline value class BearerToken(val token: String) { fun toHeader(): String = \u0026#34;Bearer $token\u0026#34; } @JvmInline value class Url(val value: String) { init { require(value.startsWith(\u0026#34;http://\u0026#34;) || value.startsWith(\u0026#34;https://\u0026#34;)) { \u0026#34;URL inválida: $value\u0026#34; } } } fun callApi(url: Url, token: BearerToken): JsonString { // Impossível passar token onde deveria ser URL e vice-versa // ... return JsonString(\u0026#34;\u0026#34;\u0026#34;{\u0026#34;status\u0026#34;: \u0026#34;ok\u0026#34;}\u0026#34;\u0026#34;\u0026#34;) } Performance: Value Classes vs Data Classes A principal vantagem de value classes sobre data classes é a ausência de alocação no heap na maioria dos cenários:\n// Data class — SEMPRE aloca um objeto no heap data class UserIdData(val value: Long) // Value class — NÃO aloca objeto (inlined como Long) @JvmInline value class UserIdValue(val value: Long) fun processDataId(id: UserIdData) = id.value * 2 fun processValueId(id: UserIdValue) = id.value * 2 // No bytecode: // processDataId recebe um objeto UserIdData // processValueId recebe um long primitivo Quando Ocorre Boxing? Value classes são alocadas no heap (boxing) em cenários específicos:\n@JvmInline value class Name(val value: String) // ❌ Boxing ocorre aqui: val nullable: Name? = Name(\u0026#34;Kotlin\u0026#34;) // Nullable → boxing val list: List\u0026lt;Name\u0026gt; = listOf(Name(\u0026#34;A\u0026#34;)) // Generic → boxing val any: Any = Name(\u0026#34;B\u0026#34;) // Upcasting → boxing // ✅ Sem boxing aqui: val name: Name = Name(\u0026#34;Kotlin\u0026#34;) // Uso direto → inlined fun greet(name: Name) = \u0026#34;Olá, ${name.value}\u0026#34; // Parâmetro → inlined Na prática, para a maioria dos casos de uso (parâmetros de função, variáveis locais, retornos), o compilador elimina a alocação. O boxing acontece apenas quando o tipo precisa ser \u0026ldquo;apagado\u0026rdquo; por nullability ou generics.\nValue Classes e Interfaces Value classes podem implementar interfaces, o que abre possibilidades interessantes:\ninterface Identifiable { val id: String } @JvmInline value class SkuCode(val code: String) : Identifiable { override val id: String get() = code } @JvmInline value class Barcode(val code: String) : Identifiable { override val id: String get() = code } fun logIdentifiable(item: Identifiable) { println(\u0026#34;Processing: ${item.id}\u0026#34;) } Atenção: quando uma value class é usada como interface (upcast), ocorre boxing. Use interfaces com value classes conscientemente.\nLimitações Value classes têm algumas restrições importantes:\nApenas uma propriedade no construtor primário (por enquanto) Não podem ter lateinit ou propriedades delegadas Não podem participar de hierarquias de classe — não podem ser open, abstract ou sealed Boxing em contextos genéricos e nullable Não podem ter backing fields além da propriedade primária Se você precisa de mais de uma propriedade, use uma data class ou aguarde futuras versões do Kotlin com suporte a multi-property value classes.\nPara representar estados complexos com restrições de tipo, considere combinar value classes com sealed classes:\n@JvmInline value class OrderId(val value: Long) sealed interface OrderStatus { data class Pending(val orderId: OrderId) : OrderStatus data class Shipped(val orderId: OrderId, val trackingCode: String) : OrderStatus data class Delivered(val orderId: OrderId) : OrderStatus } Comparação Rápida Aspecto Value Class Data Class Type Alias Type safety ✅ Tipo distinto ✅ Tipo distinto ❌ Mesmo tipo Alocação heap ❌ Geralmente não ✅ Sempre N/A Múltiplas props ❌ Apenas uma ✅ Sim N/A equals/hashCode ✅ Automático ✅ Automático N/A copy() ❌ Não ✅ Sim N/A Boas Práticas Use value classes para IDs e identificadores — é o caso de uso com melhor relação custo-benefício Adicione validação no init — falhe rápido em vez de propagar dados inválidos Prefira value classes a type aliases quando precisar de type safety real Evite em contextos genéricos se performance for crítica (listas, maps, nullable) Combine com sealed classes para modelagem de domínio expressiva Documente o comportamento de boxing para o time entender quando a alocação acontece Conclusão Value classes são uma das features mais subestimadas do Kotlin. Elas oferecem type safety sem custo de runtime na maioria dos cenários — algo que poucas linguagens conseguem entregar. Se você quer escrever código Kotlin mais seguro, mais expressivo e mais performático, comece adotando value classes nos seus IDs e tipos primitivos de domínio. Para mais sobre modelagem e boas práticas, confira nosso guia de design patterns em Kotlin e o artigo sobre scope functions.\nSe você vem de outras linguagens, vale notar que Go usa type definitions com custo zero semelhante, enquanto Rust tem o padrão newtype que inspira as value classes do Kotlin. Já em Python, o módulo typing oferece NewType para segurança estática, embora sem os ganhos de performance em runtime que o Kotlin proporciona.\n","permalink":"https://kotlin.dev.br/blog/kotlin-value-classes/","summary":"\u003cp\u003eQuantas vezes você já passou um \u003ccode\u003eString\u003c/code\u003e onde deveria ser um ID, ou confundiu metros com quilômetros porque ambos eram \u003ccode\u003eDouble\u003c/code\u003e? Esses bugs silenciosos são comuns em projetos Kotlin — e as \u003cstrong\u003evalue classes\u003c/strong\u003e existem justamente para eliminá-los. Neste guia, vamos explorar tudo sobre value classes: desde a sintaxe básica até padrões avançados de modelagem de domínio, sempre com foco em performance e type safety.\u003c/p\u003e\n\u003ch2 id=\"o-que-são-value-classes\"\u003eO que São Value Classes?\u003c/h2\u003e\n\u003cp\u003eValue classes (anteriormente chamadas de inline classes) são um recurso do Kotlin que permite criar tipos wrapper \u003cstrong\u003esem custo de alocação em runtime\u003c/strong\u003e. O compilador substitui a value class pelo valor interno sempre que possível, eliminando a criação de objetos no heap.\u003c/p\u003e","title":"Value Classes em Kotlin: Performance e Type Safety | Kotlin Brasil"},{"content":"Se o build do seu projeto Kotlin demora mais do que deveria, há uma boa chance de que o kapt (Kotlin Annotation Processing Tool) seja o vilão. A boa notícia é que o KSP — Kotlin Symbol Processing — chegou para substituí-lo com ganhos reais de performance e uma API muito mais amigável. Neste guia, vamos explorar tudo sobre KSP: o que é, como configurar, como migrar do kapt e até como criar seu próprio processador.\nO que é KSP? KSP é uma API desenvolvida pelo Google para processar símbolos Kotlin em tempo de compilação. Diferente do kapt, que precisa gerar stubs Java para funcionar, o KSP trabalha diretamente com a árvore de símbolos do compilador Kotlin. Isso significa:\nBuilds até 2x mais rápidos — sem a etapa de geração de stubs Java API nativa em Kotlin — trabalha com tipos Kotlin diretamente (nullable, extension functions, etc.) Multiplatform ready — funciona com Kotlin Multiplatform, diferente do kapt que é JVM-only Incrementalidade — KSP suporta processamento incremental out-of-the-box KSP vs kapt: Comparação de Performance A diferença de performance é significativa. Em benchmarks do próprio Google com projetos reais:\nMétrica kapt KSP Melhoria Build limpo 120s 65s ~45% mais rápido Build incremental 40s 18s ~55% mais rápido Uso de memória Alto Moderado ~30% menos O motivo principal é simples: kapt precisa rodar o compilador Java (javac) sobre stubs gerados, enquanto KSP pula essa etapa completamente. Se você usa Gradle no seu projeto Kotlin, a migração para KSP é uma das otimizações com melhor custo-benefício.\nConfigurando KSP no Projeto Passo 1: Adicionar o plugin KSP No seu build.gradle.kts do projeto raiz:\nplugins { id(\u0026#34;com.google.devtools.ksp\u0026#34;) version \u0026#34;2.1.10-1.0.29\u0026#34; apply false } Passo 2: Aplicar no módulo No build.gradle.kts do módulo:\nplugins { id(\u0026#34;org.jetbrains.kotlin.jvm\u0026#34;) id(\u0026#34;com.google.devtools.ksp\u0026#34;) } dependencies { // Exemplo com Room implementation(\u0026#34;androidx.room:room-runtime:2.7.0\u0026#34;) ksp(\u0026#34;androidx.room:room-compiler:2.7.0\u0026#34;) // Exemplo com Moshi implementation(\u0026#34;com.squareup.moshi:moshi:1.15.2\u0026#34;) ksp(\u0026#34;com.squareup.moshi:moshi-kotlin-codegen:1.15.2\u0026#34;) } Note que onde antes usávamos kapt(...), agora usamos ksp(...). A mudança na configuração é mínima.\nPasso 3: Configurar argumentos do KSP (opcional) ksp { arg(\u0026#34;room.schemaLocation\u0026#34;, \u0026#34;$projectDir/schemas\u0026#34;) arg(\u0026#34;room.incremental\u0026#34;, \u0026#34;true\u0026#34;) arg(\u0026#34;room.generateKotlin\u0026#34;, \u0026#34;true\u0026#34;) } Migrando do kapt para KSP A migração é geralmente simples, mas exige atenção. Aqui está o checklist:\n1. Verifique se suas bibliotecas suportam KSP:\nBiblioteca Suporte KSP Desde Room ✅ 2.4.0 Moshi ✅ 1.13.0 Hilt/Dagger ✅ 2.48 Glide ✅ 4.14.0 Koin Annotations ✅ 1.1.0 MapStruct ⚠️ Parcial — 2. Substitua as dependências:\n// Antes (kapt) plugins { kotlin(\u0026#34;kapt\u0026#34;) } dependencies { kapt(\u0026#34;androidx.room:room-compiler:2.7.0\u0026#34;) } // Depois (KSP) plugins { id(\u0026#34;com.google.devtools.ksp\u0026#34;) } dependencies { ksp(\u0026#34;androidx.room:room-compiler:2.7.0\u0026#34;) } 3. Remova o plugin kapt se nenhuma outra dependência precisar dele:\n// Remova esta linha do plugins {} kotlin(\u0026#34;kapt\u0026#34;) 4. Limpe e rebuild:\n./gradlew clean build Se você está migrando um projeto Spring Boot com Kotlin, atenção: o Dagger/Hilt já suporta KSP, mas verifique a compatibilidade com o Spring annotation processing.\nBibliotecas Populares com Suporte KSP Room (Android) Room foi uma das primeiras bibliotecas a adotar KSP. Com a flag room.generateKotlin = true, o código gerado é Kotlin puro:\n@Database(entities = [User::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao } @Entity data class User( @PrimaryKey val id: Int, val name: String, val email: String ) @Dao interface UserDao { @Query(\u0026#34;SELECT * FROM user\u0026#34;) suspend fun getAll(): List\u0026lt;User\u0026gt; @Insert suspend fun insert(user: User) } Moshi (Serialização JSON) Moshi com KSP gera adaptadores JSON sem reflection:\n@JsonClass(generateAdapter = true) data class ApiResponse( @Json(name = \u0026#34;status_code\u0026#34;) val statusCode: Int, val message: String, val data: List\u0026lt;Item\u0026gt; ) Criando um Processador KSP Simples Vamos criar um processador que gera automaticamente um método toMap() para data classes anotadas. Isso é útil para entender como KSP funciona por dentro — e é o tipo de conhecimento que impressiona em entrevistas técnicas de Kotlin.\nPasso 1: Definir a anotação // annotations/src/main/kotlin/ToMap.kt @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.SOURCE) annotation class ToMap Passo 2: Criar o processador // processor/src/main/kotlin/ToMapProcessor.kt class ToMapProcessor( private val codeGenerator: CodeGenerator, private val logger: KSPLogger ) : SymbolProcessor { override fun process(resolver: Resolver): List\u0026lt;KSAnnotated\u0026gt; { val symbols = resolver .getSymbolsWithAnnotation(\u0026#34;com.example.ToMap\u0026#34;) .filterIsInstance\u0026lt;KSClassDeclaration\u0026gt;() symbols.forEach { classDeclaration -\u0026gt; if (classDeclaration.classKind != ClassKind.CLASS) { logger.error(\u0026#34;@ToMap só pode ser aplicado em classes\u0026#34;, classDeclaration) return@forEach } generateToMap(classDeclaration) } return emptyList() } private fun generateToMap(classDecl: KSClassDeclaration) { val className = classDecl.simpleName.asString() val packageName = classDecl.packageName.asString() val properties = classDecl.getAllProperties() val file = codeGenerator.createNewFile( Dependencies(true, classDecl.containingFile!!), packageName, \u0026#34;${className}Extensions\u0026#34; ) file.bufferedWriter().use { writer -\u0026gt; writer.write(\u0026#34;package $packageName\\n\\n\u0026#34;) writer.write(\u0026#34;fun $className.toMap(): Map\u0026lt;String, Any?\u0026gt; = mapOf(\\n\u0026#34;) properties.forEach { prop -\u0026gt; val propName = prop.simpleName.asString() writer.write(\u0026#34; \\\u0026#34;$propName\\\u0026#34; to this.$propName,\\n\u0026#34;) } writer.write(\u0026#34;)\\n\u0026#34;) } } } class ToMapProcessorProvider : SymbolProcessorProvider { override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { return ToMapProcessor(environment.codeGenerator, environment.logger) } } Passo 3: Usar a anotação @ToMap data class Product( val id: Long, val name: String, val price: Double ) // Código gerado automaticamente pelo KSP: // fun Product.toMap(): Map\u0026lt;String, Any?\u0026gt; = mapOf( // \u0026#34;id\u0026#34; to this.id, // \u0026#34;name\u0026#34; to this.name, // \u0026#34;price\u0026#34; to this.price, // ) fun main() { val product = Product(1, \u0026#34;Kotlin in Action\u0026#34;, 49.90) println(product.toMap()) // {id=1, name=Kotlin in Action, price=49.9} } Essa abordagem com extension functions geradas por KSP é um padrão poderoso que combina bem com DSLs em Kotlin.\nDicas e Boas Práticas Sempre prefira KSP ao kapt em projetos novos — não há razão para usar kapt em 2026 Use processamento incremental — KSP suporta nativamente, mas certifique-se de declarar as dependências corretas no Dependencies(...) Teste seus processadores — use a biblioteca com.google.devtools.ksp:symbol-processing-api para testes unitários Evite misturar kapt e KSP no mesmo módulo — funciona, mas perde parte dos ganhos de performance Monitore os tempos de build — use ./gradlew --scan para verificar se a migração realmente melhorou Quando Ainda Usar kapt? Existem raros cenários onde o kapt ainda é necessário:\nBibliotecas Java-only que não migraram para KSP (cada vez mais raro) Processadores que dependem de APIs específicas do javax.annotation.processing Projetos legados em fase de migração gradual Mas a tendência é clara: o kapt está em modo de manutenção e o KSP é o futuro. Se você está construindo APIs com Ktor ou projetos Kotlin Multiplatform, KSP é a escolha natural.\nConclusão KSP não é apenas uma melhoria incremental sobre o kapt — é uma mudança de paradigma no processamento de anotações em Kotlin. Com builds mais rápidos, uma API Kotlin-native e suporte a multiplatform, não há motivo para não migrar. Se você quer mergulhar mais fundo no ecossistema Kotlin, explore nossos guias de design patterns e testes com JUnit5 e MockK.\nPara quem vem de outras linguagens, vale comparar a abordagem de geração de código do Kotlin com as macros procedurais do Rust ou os geradores de código em Go com go generate. Já em Python, metaclasses e decorators cumprem um papel semelhante ao KSP para geração dinâmica de código.\n","permalink":"https://kotlin.dev.br/blog/kotlin-ksp-guia-completo/","summary":"\u003cp\u003eSe o build do seu projeto Kotlin demora mais do que deveria, há uma boa chance de que o \u003cstrong\u003ekapt\u003c/strong\u003e (Kotlin Annotation Processing Tool) seja o vilão. A boa notícia é que o \u003cstrong\u003eKSP — Kotlin Symbol Processing\u003c/strong\u003e — chegou para substituí-lo com ganhos reais de performance e uma API muito mais amigável. Neste guia, vamos explorar tudo sobre KSP: o que é, como configurar, como migrar do kapt e até como criar seu próprio processador.\u003c/p\u003e","title":"KSP (Kotlin Symbol Processing): Guia Completo | Kotlin Brasil"},{"content":"Sobre a vagaA AB InBev busca um(a) Coordenador(a) de Engenharia para atuação presencial em Campinas, São Paulo. A posição é de nível pleno e envolve desenvolvimento e coordenação técnica em ambientes com Java, Kotlin, APIs REST e microsserviços.\nResponsabilidadesCoordenar atividades de engenharia de software e apoiar decisões técnicas do time.Trabalhar com arquitetura baseada em microsserviços e integração via APIs REST.Aplicar boas práticas de design patterns, testes unitários e qualidade de código.Colaborar com times ágeis em rotinas de Scrum e entrega contínua de valor.RequisitosExperiência com Java e Kotlin.Conhecimento em APIs REST e arquitetura de microsserviços.Vivência com design patterns e testes unitários.Experiência em times ágeis, especialmente com Agile/Scrum.Disponibilidade para atuação presencial em Campinas, São Paulo. ","permalink":"https://kotlin.dev.br/vagas/kmx0jai2yryrvl39-ab-inbev-coordenador-a-de-engenharia/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA AB InBev busca um(a) Coordenador(a) de Engenharia para atuação presencial em Campinas, São Paulo. A posição é de nível pleno e envolve desenvolvimento e coordenação técnica em ambientes com Java, Kotlin, APIs REST e microsserviços.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eCoordenar atividades de engenharia de software e apoiar decisões técnicas do time.\u003c/li\u003e\u003cli\u003eTrabalhar com arquitetura baseada em microsserviços e integração via APIs REST.\u003c/li\u003e\u003cli\u003eAplicar boas práticas de design patterns, testes unitários e qualidade de código.\u003c/li\u003e\u003cli\u003eColaborar com times ágeis em rotinas de Scrum e entrega contínua de valor.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Java e Kotlin.\u003c/li\u003e\u003cli\u003eConhecimento em APIs REST e arquitetura de microsserviços.\u003c/li\u003e\u003cli\u003eVivência com design patterns e testes unitários.\u003c/li\u003e\u003cli\u003eExperiência em times ágeis, especialmente com Agile/Scrum.\u003c/li\u003e\u003cli\u003eDisponibilidade para atuação presencial em Campinas, São Paulo.\u003c/li\u003e\u003c/ul\u003e","title":"Coordenador(a) de Engenharia"},{"content":"Se você programa em Kotlin e já sentiu que o tratamento de erros com exceções é frágil, imprevisível e difícil de compor, a biblioteca Arrow pode mudar completamente sua perspectiva. Arrow é a principal biblioteca de programação funcional para Kotlin — e em 2026, com a Raise DSL e integração nativa com coroutines, ela está mais acessível e poderosa do que nunca.\nO que é Arrow? Arrow é uma biblioteca open-source que traz conceitos de programação funcional tipada para Kotlin. Diferente de abordagens acadêmicas, Arrow foi projetada para ser prática — ela resolve problemas reais de tratamento de erros, composição de operações e modelagem de domínio.\nOs pilares principais são:\nEither — representar sucesso ou falha sem exceções Option — lidar com ausência de valor de forma explícita Raise DSL — a abordagem moderna para error handling composável Validated — acumular múltiplos erros em vez de parar no primeiro Arrow não é um framework que exige que você reescreva tudo. Você pode adotar uma peça de cada vez, no ritmo do seu projeto.\nConfigurando Arrow no projeto Adicione ao seu build.gradle.kts:\ndependencies { implementation(\u0026#34;io.arrow-kt:arrow-core:1.2.4\u0026#34;) implementation(\u0026#34;io.arrow-kt:arrow-fx-coroutines:1.2.4\u0026#34;) } A dependência arrow-core traz Either, Option e Raise. Já arrow-fx-coroutines adiciona integração com coroutines do Kotlin para operações assíncronas.\nEither — Erros sem exceções O problema com exceções é que elas são invisíveis na assinatura da função. Quando você chama buscarUsuario(id), não tem como saber, olhando a assinatura, que ela pode lançar UsuarioNaoEncontradoException. Isso leva a bugs em produção.\nEither resolve isso tornando o erro explícito no tipo de retorno:\nimport arrow.core.Either import arrow.core.left import arrow.core.right sealed class ErroUsuario { data class NaoEncontrado(val id: Long) : ErroUsuario() data class EmailInvalido(val email: String) : ErroUsuario() } data class Usuario(val id: Long, val nome: String, val email: String) fun buscarUsuario(id: Long): Either\u0026lt;ErroUsuario, Usuario\u0026gt; { val usuario = repository.findById(id) return if (usuario != null) { usuario.right() } else { ErroUsuario.NaoEncontrado(id).left() } } Agora, quem chama buscarUsuario sabe que a função pode falhar e é obrigado a lidar com isso:\nwhen (val resultado = buscarUsuario(42L)) { is Either.Left -\u0026gt; println(\u0026#34;Erro: ${resultado.value}\u0026#34;) is Either.Right -\u0026gt; println(\u0026#34;Encontrado: ${resultado.value.nome}\u0026#34;) } A grande vantagem é a composição. Com map, flatMap e fold, você encadeia operações sem perder o controle:\nfun processarPedido(usuarioId: Long): Either\u0026lt;ErroUsuario, Pedido\u0026gt; { return buscarUsuario(usuarioId) .map { usuario -\u0026gt; criarPedido(usuario) } .flatMap { pedido -\u0026gt; validarPedido(pedido) } } Se qualquer etapa falhar, o erro é propagado automaticamente — sem try/catch, sem exceções voando.\nRaise DSL — A abordagem moderna A partir do Arrow 1.2, a Raise DSL se tornou a forma recomendada de trabalhar com erros. Ela combina a segurança do Either com uma sintaxe imperativa que parece código \u0026ldquo;normal\u0026rdquo;:\nimport arrow.core.raise.either import arrow.core.raise.Raise import arrow.core.raise.ensure fun Raise\u0026lt;ErroUsuario\u0026gt;.buscarUsuario(id: Long): Usuario { val usuario = repository.findById(id) ensure(usuario != null) { ErroUsuario.NaoEncontrado(id) } return usuario } fun Raise\u0026lt;ErroUsuario\u0026gt;.validarEmail(email: String): String { ensure(email.contains(\u0026#34;@\u0026#34;)) { ErroUsuario.EmailInvalido(email) } return email } fun Raise\u0026lt;ErroUsuario\u0026gt;.criarUsuario(nome: String, email: String): Usuario { val emailValidado = validarEmail(email) val usuario = Usuario(0L, nome, emailValidado) return repository.salvar(usuario) } O bloco either { } converte o resultado para Either:\nval resultado: Either\u0026lt;ErroUsuario, Usuario\u0026gt; = either { val usuario = buscarUsuario(42L) val atualizado = usuario.copy(nome = \u0026#34;Novo Nome\u0026#34;) repository.salvar(atualizado) } O código dentro do either { } parece imperativo — sem map, flatMap ou encadeamento manual. Mas a segurança é a mesma: se qualquer função com Raise falhar, a execução é interrompida e o erro é retornado como Either.Left.\nEssa é a grande inovação do Raise: você escreve código que parece procedural mas é funcional.\nOption — Ausência explícita de valor Kotlin já tem null safety com ?, mas Option do Arrow ainda tem seu lugar quando você quer uma API mais funcional e composável:\nimport arrow.core.Option import arrow.core.Some import arrow.core.None import arrow.core.toOption fun buscarConfig(chave: String): Option\u0026lt;String\u0026gt; { return System.getenv(chave).toOption() } val porta = buscarConfig(\u0026#34;PORT\u0026#34;) .map { it.toInt() } .getOrElse { 8080 } Na prática, muitos projetos Kotlin preferem usar ? diretamente. Mas Option brilha quando você precisa de interoperabilidade com outras construções do Arrow ou quando trabalha com coleções de valores opcionais.\nAcumulando erros com Validated e zipOrAccumulate Um caso comum é validação de formulários: você quer mostrar todos os erros de uma vez, não parar no primeiro. O Arrow oferece zipOrAccumulate para isso:\nimport arrow.core.raise.either import arrow.core.raise.zipOrAccumulate data class RegistroUsuario(val nome: String, val email: String, val idade: Int) fun validarRegistro( nome: String, email: String, idade: Int ): Either\u0026lt;List\u0026lt;String\u0026gt;, RegistroUsuario\u0026gt; = either { zipOrAccumulate( { ensure(nome.isNotBlank()) { \u0026#34;Nome não pode estar vazio\u0026#34; } }, { ensure(email.contains(\u0026#34;@\u0026#34;)) { \u0026#34;Email inválido\u0026#34; } }, { ensure(idade \u0026gt;= 18) { \u0026#34;Deve ter pelo menos 18 anos\u0026#34; } } ) { _, _, _ -\u0026gt; RegistroUsuario(nome, email, idade) } } Se o nome estiver vazio e o email for inválido e a idade for menor que 18, todos os três erros são retornados juntos. Isso é impossível de fazer elegantemente com exceções.\nArrow e coroutines Arrow se integra perfeitamente com coroutines do Kotlin. Operações assíncronas podem ser compostas mantendo o tratamento de erros funcional:\nimport arrow.fx.coroutines.parZip suspend fun carregarDashboard(userId: Long): Either\u0026lt;Erro, Dashboard\u0026gt; = either { parZip( { buscarPerfil(userId).bind() }, { buscarPedidos(userId).bind() }, { buscarNotificacoes(userId).bind() } ) { perfil, pedidos, notificacoes -\u0026gt; Dashboard(perfil, pedidos, notificacoes) } } O parZip executa as três operações em paralelo e combina os resultados. Se qualquer uma falhar, o erro é propagado e as outras são canceladas. É concorrência estruturada com error handling funcional — o melhor dos dois mundos. Se você trabalha com Python e asyncio, vai notar que o parZip oferece uma experiência mais segura que o asyncio.gather, já que o sistema de tipos garante o tratamento de erros em tempo de compilação.\nPor que Arrow em 2026? O ecossistema Kotlin está amadurecendo rapidamente. Em 2026, vemos Arrow sendo adotado por equipes que buscam:\nCódigo mais previsível — sem surpresas de exceções não tratadas Melhor testabilidade — funções puras com Either são fáceis de testar (veja nosso guia de testes com JUnit 5 e MockK) Composição natural — encadear operações que podem falhar sem aninhamento de try/catch Interoperabilidade — Arrow funciona com Spring Boot, Ktor, Android e qualquer projeto Kotlin Se você já usa DSLs em Kotlin, a Raise DSL do Arrow vai parecer completamente natural. A abordagem é a mesma: usar os recursos da linguagem para criar APIs expressivas e seguras.\nArrow vs. exceções — Quando usar cada um Arrow não é para substituir todas as exceções. Aqui está uma diretriz prática:\nCenário Abordagem recomendada Erro de programação (bug) Exceção (IllegalStateException) Erro de domínio esperado Either / Raise Validação de entrada zipOrAccumulate Ausência de valor Kotlin nullable (?) ou Option Erro de infraestrutura Exceção ou Either (depende do contexto) A regra geral: se o chamador precisa lidar com o erro como parte do fluxo normal, use Either. Se é um bug que não deveria acontecer, use exceções.\nComeçando com Arrow gradualmente Você não precisa adotar Arrow em todo o projeto de uma vez. Uma estratégia eficiente:\nComece pela camada de serviço — substitua exceções de domínio por Either Adote Raise DSL nos novos serviços Use zipOrAccumulate em validações de formulários e APIs Integre com coroutines para operações assíncronas Cada passo traz benefícios imediatos sem exigir uma reescrita completa.\nConclusão Arrow transformou a forma como desenvolvedores Kotlin lidam com erros e efeitos colaterais. Com a Raise DSL, a barreira de entrada caiu drasticamente — você não precisa ser um expert em programação funcional para se beneficiar. O código fica mais seguro, mais composável e mais fácil de testar.\nSe você está construindo aplicações Kotlin que precisam de robustez no tratamento de erros — seja backend com Spring Boot, APIs com Ktor ou apps Android — Arrow merece um lugar no seu toolbox. Rust também abraça paradigmas funcionais com Result types e pattern matching, e Go adota retorno explícito de erros como padrão da linguagem — ambas abordagens que inspiram o uso de Either no Kotlin. Comece com Either, evolua para Raise, e descubra como programação funcional pode ser prática e idiomática em Kotlin.\n","permalink":"https://kotlin.dev.br/blog/kotlin-arrow-programacao-funcional/","summary":"\u003cp\u003eSe você programa em Kotlin e já sentiu que o tratamento de erros com exceções é frágil, imprevisível e difícil de compor, a biblioteca \u003cstrong\u003eArrow\u003c/strong\u003e pode mudar completamente sua perspectiva. Arrow é a principal biblioteca de programação funcional para Kotlin — e em 2026, com a \u003cstrong\u003eRaise DSL\u003c/strong\u003e e integração nativa com coroutines, ela está mais acessível e poderosa do que nunca.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-arrow\"\u003eO que é Arrow?\u003c/h2\u003e\n\u003cp\u003eArrow é uma biblioteca open-source que traz conceitos de programação funcional tipada para Kotlin. Diferente de abordagens acadêmicas, Arrow foi projetada para ser \u003cstrong\u003eprática\u003c/strong\u003e — ela resolve problemas reais de tratamento de erros, composição de operações e modelagem de domínio.\u003c/p\u003e","title":"Arrow em Kotlin — Programação Funcional na Prática | Kotlin Brasil"},{"content":"Testar código em Kotlin é uma experiência completamente diferente de testar em Java. A linguagem oferece recursos como data classes, extension functions, coroutines e null safety que mudam a forma como escrevemos — e testamos — nosso código. Neste guia prático, vamos explorar como usar JUnit 5 e MockK para escrever testes unitários idiomáticos em Kotlin.\nPor que JUnit 5 + MockK? No ecossistema Java, a combinação clássica é JUnit + Mockito. Funciona em Kotlin? Sim, mas com ressalvas. Mockito tem dificuldades com classes final (que são o padrão em Kotlin), exige workarounds com mockito-kotlin e não suporta nativamente coroutines.\nMockK foi criado especificamente para Kotlin. Ele entende classes finais, oferece uma DSL fluente e idiomática, e suporta coroutines, relaxed mocks e muito mais — tudo de forma nativa.\nJá o JUnit 5 (Jupiter) trouxe melhorias significativas sobre o JUnit 4: testes parametrizados mais poderosos, extensões modulares, lifecycle hooks e suporte a Kotlin muito mais robusto.\nConfigurando o projeto Adicione as dependências no seu build.gradle.kts:\ndependencies { testImplementation(\u0026#34;org.junit.jupiter:junit-jupiter:5.10.2\u0026#34;) testImplementation(\u0026#34;io.mockk:mockk:1.13.10\u0026#34;) testImplementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.0\u0026#34;) } tasks.test { useJUnitPlatform() } Com essas três dependências, você tem tudo o que precisa: JUnit 5 como framework de teste, MockK para mocking e a biblioteca de testes de coroutines.\nEscrevendo seu primeiro teste Vamos começar com um exemplo simples. Imagine um serviço que calcula descontos:\nclass DescontoService { fun calcularDesconto(preco: Double, percentual: Int): Double { require(percentual in 0..100) { \u0026#34;Percentual deve estar entre 0 e 100\u0026#34; } return preco * (1 - percentual / 100.0) } } O teste com JUnit 5 fica assim:\nimport org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows class DescontoServiceTest { private val service = DescontoService() @Test fun `deve aplicar desconto de 20 por cento`() { val resultado = service.calcularDesconto(100.0, 20) assertEquals(80.0, resultado, 0.01) } @Test fun `deve lancar excecao para percentual invalido`() { assertThrows\u0026lt;IllegalArgumentException\u0026gt; { service.calcularDesconto(100.0, 150) } } } Note o uso de backticks nos nomes dos testes — um recurso do Kotlin que permite nomes descritivos e legíveis. Esse é um dos grandes diferenciais ao testar em Kotlin versus Java.\nMocking com MockK — O básico O poder do MockK aparece quando você precisa isolar dependências. Vamos considerar um repositório e um serviço:\ninterface UsuarioRepository { fun buscarPorId(id: Long): Usuario? fun salvar(usuario: Usuario): Usuario } data class Usuario(val id: Long, val nome: String, val email: String) class UsuarioService(private val repository: UsuarioRepository) { fun obterUsuario(id: Long): Usuario { return repository.buscarPorId(id) ?: throw NoSuchElementException(\u0026#34;Usuário não encontrado\u0026#34;) } } Com MockK, o teste fica extremamente limpo:\nimport io.mockk.* import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import kotlin.test.assertEquals class UsuarioServiceTest { private val repository = mockk\u0026lt;UsuarioRepository\u0026gt;() private val service = UsuarioService(repository) @Test fun `deve retornar usuario quando encontrado`() { val usuario = Usuario(1L, \u0026#34;Maria\u0026#34;, \u0026#34;maria@email.com\u0026#34;) every { repository.buscarPorId(1L) } returns usuario val resultado = service.obterUsuario(1L) assertEquals(\u0026#34;Maria\u0026#34;, resultado.nome) verify(exactly = 1) { repository.buscarPorId(1L) } } @Test fun `deve lancar excecao quando usuario nao encontrado`() { every { repository.buscarPorId(any()) } returns null assertThrows\u0026lt;NoSuchElementException\u0026gt; { service.obterUsuario(99L) } } } A sintaxe every { ... } returns ... é a DSL do MockK. É declarativa, fácil de ler e não exige casts estranhos como acontece com Mockito em Kotlin.\nCapturando argumentos com Slot Às vezes, você precisa inspecionar o que foi passado para um mock. O slot do MockK resolve isso:\n@Test fun `deve salvar usuario com nome formatado`() { val slot = slot\u0026lt;Usuario\u0026gt;() every { repository.salvar(capture(slot)) } answers { slot.captured } val service = UsuarioService(repository) service.criarUsuario(\u0026#34;joão silva\u0026#34;, \u0026#34;joao@email.com\u0026#34;) assertEquals(\u0026#34;João Silva\u0026#34;, slot.captured.nome) } Isso é especialmente útil quando seu serviço transforma dados antes de salvar — você captura exatamente o que foi enviado ao repositório.\nTestando coroutines com coEvery Kotlin brilha em código assíncrono com coroutines, e o MockK suporta isso nativamente com coEvery e coVerify:\ninterface NotificacaoService { suspend fun enviar(usuarioId: Long, mensagem: String): Boolean } class PedidoService( private val repository: UsuarioRepository, private val notificacao: NotificacaoService ) { suspend fun processarPedido(usuarioId: Long) { val usuario = repository.buscarPorId(usuarioId) ?: throw NoSuchElementException(\u0026#34;Usuário não encontrado\u0026#34;) notificacao.enviar(usuarioId, \u0026#34;Pedido processado, ${usuario.nome}!\u0026#34;) } } O teste usa runTest da biblioteca kotlinx-coroutines-test:\nimport kotlinx.coroutines.test.runTest import io.mockk.* import org.junit.jupiter.api.Test class PedidoServiceTest { private val repository = mockk\u0026lt;UsuarioRepository\u0026gt;() private val notificacao = mockk\u0026lt;NotificacaoService\u0026gt;() private val service = PedidoService(repository, notificacao) @Test fun `deve enviar notificacao ao processar pedido`() = runTest { val usuario = Usuario(1L, \u0026#34;Carlos\u0026#34;, \u0026#34;carlos@email.com\u0026#34;) every { repository.buscarPorId(1L) } returns usuario coEvery { notificacao.enviar(any(), any()) } returns true service.processarPedido(1L) coVerify { notificacao.enviar(1L, \u0026#34;Pedido processado, Carlos!\u0026#34;) } } } O coEvery e coVerify são as versões suspending dos every e verify tradicionais. Sem eles, testar código com coroutines seria muito mais trabalhoso.\nRelaxed mocks e spy Nem sempre você quer configurar cada chamada de um mock. O relaxed mock retorna valores padrão para qualquer chamada não configurada:\nval repository = mockk\u0026lt;UsuarioRepository\u0026gt;(relaxed = true) // repository.buscarPorId(1L) retorna null (valor padrão para tipo nullable) // repository.salvar(usuario) retorna um Usuario com valores padrão Já o spy permite mockar parcialmente um objeto real:\nval service = spyk(UsuarioService(repository)) every { service.validarEmail(any()) } returns true // Outras funções continuam com a implementação real Boas práticas para testes em Kotlin 1. Use nomes descritivos com backticks @Test fun `deve calcular frete grátis para compras acima de R$200`() { } 2. Organize com @Nested O JUnit 5 permite agrupar testes relacionados com @Nested:\nclass CarrinhoServiceTest { @Nested inner class `Ao adicionar item` { @Test fun `deve atualizar o total`() { } @Test fun `deve incrementar a quantidade`() { } } @Nested inner class `Ao remover item` { @Test fun `deve recalcular o total`() { } } } 3. Use testes parametrizados @ParameterizedTest @CsvSource(\u0026#34;100.0, 10, 90.0\u0026#34;, \u0026#34;200.0, 50, 100.0\u0026#34;, \u0026#34;50.0, 0, 50.0\u0026#34;) fun `deve calcular desconto corretamente`(preco: Double, percentual: Int, esperado: Double) { assertEquals(esperado, service.calcularDesconto(preco, percentual), 0.01) } 4. Limpe os mocks entre testes @AfterEach fun tearDown() { clearAllMocks() } 5. Prefira injeção de dependência Classes que recebem dependências via construtor são infinitamente mais fáceis de testar. Se você precisa de mockk em tudo, é sinal de boa arquitetura. Se precisa de reflection ou hacks, algo pode ser melhorado no design.\nTestes vs. design patterns Se você está usando design patterns em Kotlin, como Strategy ou Observer, os testes ficam naturalmente mais simples. Padrões que favorecem composição sobre herança se alinham perfeitamente com a filosofia de MockK.\nPara projetos que usam programação funcional com Arrow, os testes também mudam de abordagem — com Either e Raise, você testa caminhos de sucesso e erro sem exceções, o que torna os testes mais previsíveis.\nConclusão A combinação de JUnit 5 + MockK é, sem dúvida, o padrão ouro para testes em Kotlin em 2026. MockK entende a linguagem nativamente, JUnit 5 oferece uma estrutura moderna e extensível, e juntos eles permitem escrever testes que são tão idiomáticos quanto o código de produção.\nSe você ainda está usando Mockito com Kotlin, considere experimentar MockK — a curva de aprendizado é baixa e os benefícios são imediatos. Comece pelos testes mais simples, explore coEvery para código assíncrono e use @Nested para organizar seus testes de forma hierárquica.\nSe você trabalha com múltiplas linguagens, vale comparar abordagens: em Python, pytest oferece fixtures e mocking com uma filosofia mais dinâmica, enquanto em Go, o pacote testing padrão favorece testes sem mocks com interfaces implícitas. Já em Rust, testes são integrados ao compilador com cargo test, garantindo segurança de memória até nos testes.\nBons testes não são um custo — são um investimento na qualidade e confiança do seu projeto.\n","permalink":"https://kotlin.dev.br/blog/kotlin-testes-junit5-mockk-guia/","summary":"\u003cp\u003eTestar código em Kotlin é uma experiência completamente diferente de testar em Java. A linguagem oferece recursos como data classes, extension functions, coroutines e null safety que mudam a forma como escrevemos — e testamos — nosso código. Neste guia prático, vamos explorar como usar \u003cstrong\u003eJUnit 5\u003c/strong\u003e e \u003cstrong\u003eMockK\u003c/strong\u003e para escrever testes unitários idiomáticos em Kotlin.\u003c/p\u003e\n\u003ch2 id=\"por-que-junit-5--mockk\"\u003ePor que JUnit 5 + MockK?\u003c/h2\u003e\n\u003cp\u003eNo ecossistema Java, a combinação clássica é JUnit + Mockito. Funciona em Kotlin? Sim, mas com ressalvas. Mockito tem dificuldades com classes \u003ccode\u003efinal\u003c/code\u003e (que são o padrão em Kotlin), exige workarounds com \u003ccode\u003emockito-kotlin\u003c/code\u003e e não suporta nativamente coroutines.\u003c/p\u003e","title":"Testes em Kotlin com JUnit 5 e MockK — Guia Prático | Kotlin Brasil"},{"content":"Sobre a vagaA GFT busca uma pessoa Desenvolvedora Java Sênior para atuação em modelo híbrido em Alphaville, São Paulo.\nRequisitosExperiência sênior com desenvolvimento em Java.Conhecimento em Kotlin e Spring Boot.Experiência com serviços em AWS.Vivência com bancos de dados PostgreSQL e DynamoDB.Conhecimento em mensageria com Kafka.Experiência com Docker e versionamento com Git.Modelo de trabalhoVaga híbrida, com atuação em Alphaville, São Paulo.\n","permalink":"https://kotlin.dev.br/vagas/nv38q9vbgbk0oq6k-gft-desenvolvedor-a-java-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA GFT busca uma pessoa Desenvolvedora Java Sênior para atuação em modelo híbrido em Alphaville, São Paulo.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com desenvolvimento em \u003cstrong\u003eJava\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em \u003cstrong\u003eKotlin\u003c/strong\u003e e \u003cstrong\u003eSpring Boot\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com serviços em \u003cstrong\u003eAWS\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eVivência com bancos de dados \u003cstrong\u003ePostgreSQL\u003c/strong\u003e e \u003cstrong\u003eDynamoDB\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eConhecimento em mensageria com \u003cstrong\u003eKafka\u003c/strong\u003e.\u003c/li\u003e\u003cli\u003eExperiência com \u003cstrong\u003eDocker\u003c/strong\u003e e versionamento com \u003cstrong\u003eGit\u003c/strong\u003e.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga híbrida, com atuação em Alphaville, São Paulo.\u003c/p\u003e","title":"Desenvolvedor(a) Java Sênior"},{"content":"Sobre a vagaA Airbnb busca uma pessoa Android Software Engineer de nível pleno para atuar remotamente no Brasil em uma plataforma de qualidade para aplicações mobile.\nStack e contextoKotlin e Android SDK.Testes Android com Espresso e Compose Test.Gradle e pipelines de CI/CD.Possível contato com AI/LLMs no contexto da plataforma.RequisitosExperiência com desenvolvimento Android em Kotlin.Vivência com automação de testes e qualidade em aplicações Android.Familiaridade com ferramentas de build e integração contínua.Disponibilidade para trabalho remoto a partir do Brasil. ","permalink":"https://kotlin.dev.br/vagas/uivdueinkyh7bfqx-airbnb-engenheiro-a-de-software-android-plataforma-de-qualidade/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Airbnb busca uma pessoa \u003cstrong\u003eAndroid Software Engineer\u003c/strong\u003e de nível pleno para atuar remotamente no Brasil em uma plataforma de qualidade para aplicações mobile.\u003c/p\u003e\u003ch3\u003eStack e contexto\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin e Android SDK.\u003c/li\u003e\u003cli\u003eTestes Android com Espresso e Compose Test.\u003c/li\u003e\u003cli\u003eGradle e pipelines de CI/CD.\u003c/li\u003e\u003cli\u003ePossível contato com AI/LLMs no contexto da plataforma.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com desenvolvimento Android em Kotlin.\u003c/li\u003e\u003cli\u003eVivência com automação de testes e qualidade em aplicações Android.\u003c/li\u003e\u003cli\u003eFamiliaridade com ferramentas de build e integração contínua.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho remoto a partir do Brasil.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de Software Android, Plataforma de Qualidade"},{"content":"Sobre a vagaA Brex busca uma pessoa Engenheira de Software Sênior Full Stack para atuar em modelo híbrido em São Paulo ou Vancouver.\nTecnologiasKotlin, Java e PythonSQL e NoSQLREST e GraphQLReact, TypeScript, ES6+ e WebpackSenioridadeVaga de nível sênior para atuação em engenharia de software full stack.\n","permalink":"https://kotlin.dev.br/vagas/70ldd45pu9y8v2u7-brex-engenheiro-a-de-software-senior-full-stack/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Brex busca uma pessoa Engenheira de Software Sênior Full Stack para atuar em modelo híbrido em São Paulo ou Vancouver.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java e Python\u003c/li\u003e\u003cli\u003eSQL e NoSQL\u003c/li\u003e\u003cli\u003eREST e GraphQL\u003c/li\u003e\u003cli\u003eReact, TypeScript, ES6+ e Webpack\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eSenioridade\u003c/h3\u003e\u003cp\u003eVaga de nível sênior para atuação em engenharia de software full stack.\u003c/p\u003e","title":"Engenheiro(a) de Software Sênior Full Stack"},{"content":"Se você procura um framework leve, idiomático e 100% Kotlin para construir APIs REST, o Ktor é a escolha certa. Criado pela JetBrains (a mesma empresa por trás do Kotlin), o Ktor aproveita o melhor da linguagem: coroutines nativas, DSLs elegantes e tipagem forte. Neste tutorial, vamos construir uma API REST completa do zero.\nO que é o Ktor? Ktor é um framework assíncrono para criar aplicações conectadas — servidores HTTP, clientes HTTP, microserviços e WebSockets. Diferente do Spring Boot, que traz um ecossistema gigante de convenções e auto-configuração, o Ktor segue a filosofia de ser minimalista e modular: você adiciona apenas o que precisa, sem mágica escondida.\nAs principais características do Ktor incluem:\nAssincronicidade nativa: construído sobre coroutines, cada requisição é uma coroutine — sem threads bloqueadas DSL idiomático: a configuração do servidor usa DSLs de Kotlin, resultando em código expressivo e legível Multiplataforma: o cliente HTTP do Ktor roda em JVM, Native, JavaScript e WebAssembly Modular: sistema de plugins onde você instala só o que precisa (serialização, autenticação, CORS, etc.) Transparente: sem anotações mágicas, sem injeção de dependência implícita, sem proxy de classes Configurando o projeto A maneira mais rápida de iniciar é pelo Ktor Project Generator, onde você seleciona os plugins desejados e baixa o projeto pronto. Alternativamente, configure manualmente com Gradle:\n// build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.1.0\u0026#34; kotlin(\u0026#34;plugin.serialization\u0026#34;) version \u0026#34;2.1.0\u0026#34; id(\u0026#34;io.ktor.plugin\u0026#34;) version \u0026#34;3.1.1\u0026#34; } dependencies { implementation(\u0026#34;io.ktor:ktor-server-core\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-netty\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-content-negotiation\u0026#34;) implementation(\u0026#34;io.ktor:ktor-serialization-kotlinx-json\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-status-pages\u0026#34;) implementation(\u0026#34;ch.qos.logback:logback-classic:1.5.15\u0026#34;) testImplementation(\u0026#34;io.ktor:ktor-server-test-host\u0026#34;) testImplementation(\u0026#34;org.jetbrains.kotlin:kotlin-test\u0026#34;) } O plugin io.ktor.plugin facilita o build e gera o fat JAR para deploy automaticamente.\nHello World com Ktor Vamos criar o servidor mais simples possível:\nimport io.ktor.server.application.* import io.ktor.server.engine.* import io.ktor.server.netty.* import io.ktor.server.response.* import io.ktor.server.routing.* fun main() { embeddedServer(Netty, port = 8080) { routing { get(\u0026#34;/\u0026#34;) { call.respondText(\u0026#34;Olá, Ktor!\u0026#34;) } } }.start(wait = true) } Execute e acesse http://localhost:8080 — pronto, seu servidor Ktor está rodando. Note como tudo é explícito: você vê o engine (Netty), a porta, as rotas. Nada acontece sem que você configure.\nRoteamento com a DSL do Ktor O sistema de roteamento do Ktor usa uma DSL expressiva que suporta agrupamento, parâmetros de caminho e todos os métodos HTTP:\nfun Application.configureRouting() { routing { route(\u0026#34;/api/v1\u0026#34;) { get(\u0026#34;/tarefas\u0026#34;) { // Listar todas as tarefas } get(\u0026#34;/tarefas/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toIntOrNull() ?: return@get call.respondText( \u0026#34;ID inválido\u0026#34;, status = HttpStatusCode.BadRequest ) // Buscar tarefa por ID } post(\u0026#34;/tarefas\u0026#34;) { // Criar nova tarefa } put(\u0026#34;/tarefas/{id}\u0026#34;) { // Atualizar tarefa existente } delete(\u0026#34;/tarefas/{id}\u0026#34;) { // Remover tarefa } } } } A função route(\u0026quot;/api/v1\u0026quot;) agrupa todas as rotas sob um prefixo comum, evitando repetição. Os parâmetros de caminho como {id} são acessados via call.parameters.\nSerialização JSON com kotlinx.serialization Para trabalhar com JSON, o Ktor se integra nativamente com o kotlinx.serialization. Primeiro, instale o plugin de Content Negotiation:\nfun Application.configureSerialization() { install(ContentNegotiation) { json(Json { prettyPrint = true isLenient = true ignoreUnknownKeys = true }) } } Agora defina seus modelos de dados com a anotação @Serializable:\nimport kotlinx.serialization.Serializable @Serializable data class Tarefa( val id: Int = 0, val titulo: String, val descricao: String = \u0026#34;\u0026#34;, val concluida: Boolean = false ) @Serializable data class TarefaRequest( val titulo: String, val descricao: String = \u0026#34;\u0026#34; ) Exemplo completo: API CRUD de tarefas Agora vamos juntar tudo em uma API CRUD funcional. Usaremos uma lista em memória para simplificar (em produção, você conectaria a um banco de dados com Exposed ou ktorm):\nimport io.ktor.http.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* import java.util.concurrent.atomic.AtomicInteger val tarefas = mutableListOf\u0026lt;Tarefa\u0026gt;() val idCounter = AtomicInteger(0) fun Application.configureTarefasRoutes() { routing { route(\u0026#34;/api/tarefas\u0026#34;) { // GET — listar todas get { call.respond(tarefas) } // GET — buscar por ID get(\u0026#34;/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toIntOrNull() val tarefa = tarefas.find { it.id == id } if (tarefa == null) { call.respond(HttpStatusCode.NotFound, \u0026#34;Tarefa não encontrada\u0026#34;) } else { call.respond(tarefa) } } // POST — criar nova post { val request = call.receive\u0026lt;TarefaRequest\u0026gt;() val novaTarefa = Tarefa( id = idCounter.incrementAndGet(), titulo = request.titulo, descricao = request.descricao ) tarefas.add(novaTarefa) call.respond(HttpStatusCode.Created, novaTarefa) } // PUT — atualizar existente put(\u0026#34;/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toIntOrNull() val index = tarefas.indexOfFirst { it.id == id } if (index == -1) { call.respond(HttpStatusCode.NotFound, \u0026#34;Tarefa não encontrada\u0026#34;) } else { val request = call.receive\u0026lt;TarefaRequest\u0026gt;() val atualizada = tarefas[index].copy( titulo = request.titulo, descricao = request.descricao ) tarefas[index] = atualizada call.respond(atualizada) } } // DELETE — remover delete(\u0026#34;/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toIntOrNull() val removido = tarefas.removeAll { it.id == id } if (removido) { call.respond(HttpStatusCode.NoContent) } else { call.respond(HttpStatusCode.NotFound, \u0026#34;Tarefa não encontrada\u0026#34;) } } } } } Plugins essenciais O Ktor funciona com um sistema de plugins que você instala conforme a necessidade. Além do ContentNegotiation que já vimos, os mais importantes são:\nStatusPages — tratamento centralizado de erros:\ninstall(StatusPages) { exception\u0026lt;IllegalArgumentException\u0026gt; { call, cause -\u0026gt; call.respond(HttpStatusCode.BadRequest, cause.localizedMessage) } exception\u0026lt;Throwable\u0026gt; { call, cause -\u0026gt; call.respond( HttpStatusCode.InternalServerError, \u0026#34;Erro interno: ${cause.localizedMessage}\u0026#34; ) } } CORS — controle de acesso cross-origin:\ninstall(CORS) { allowHost(\u0026#34;meusite.com.br\u0026#34;) allowHeader(HttpHeaders.ContentType) allowMethod(HttpMethod.Put) allowMethod(HttpMethod.Delete) } CallLogging — logs estruturados de cada requisição:\ninstall(CallLogging) { level = Level.INFO filter { call -\u0026gt; call.request.path().startsWith(\u0026#34;/api\u0026#34;) } } Outros plugins populares incluem Authentication (JWT, OAuth, Session), WebSockets, Rate Limiting e Compression.\nKtor vs Spring Boot: quando usar cada um? Essa é uma das perguntas mais comuns entre devs Kotlin no backend. A resposta depende do contexto:\nCritério Ktor Spring Boot Filosofia Minimalista, explícito Convenção sobre configuração Curva de aprendizado Mais simples para quem sabe Kotlin Requer conhecer o ecossistema Spring Performance Mais leve, menos overhead Mais pesado, mas altamente otimizado Ecossistema Menor, mas crescendo Gigantesco, maduro Multiplataforma Sim (cliente HTTP) Apenas JVM Ideal para Microserviços, APIs leves, serverless Aplicações enterprise, monolitos Se você vem do mundo Java e já conhece Spring, a combinação Kotlin + Spring Boot oferece produtividade imediata. Se quer algo 100% Kotlin, sem heranças do mundo Java, o Ktor é o caminho natural. Para deploy serverless na AWS Lambda, o Ktor se destaca pelo cold start mais rápido.\nDeploy: fat JAR para produção O plugin do Ktor gera um fat JAR automaticamente. Basta rodar:\n./gradlew buildFatJar O JAR fica em build/libs/seu-projeto-all.jar. Para executar em produção:\njava -jar build/libs/seu-projeto-all.jar Para containerizar com Docker, um Dockerfile simples funciona:\nFROM eclipse-temurin:21-jre-alpine COPY build/libs/seu-projeto-all.jar app.jar EXPOSE 8080 ENTRYPOINT [\u0026#34;java\u0026#34;, \u0026#34;-jar\u0026#34;, \u0026#34;app.jar\u0026#34;] O Ktor também suporta GraalVM Native Image para builds nativos com cold start de milissegundos — ideal para ambientes Kubernetes e serverless.\nTestando a API Ktor tem um módulo de testes embutido que permite testar rotas sem subir o servidor de verdade:\n@Test fun `deve criar tarefa com sucesso`() = testApplication { application { configureSerialization() configureTarefasRoutes() } val response = client.post(\u0026#34;/api/tarefas\u0026#34;) { contentType(ContentType.Application.Json) setBody(\u0026#34;\u0026#34;\u0026#34;{\u0026#34;titulo\u0026#34;: \u0026#34;Estudar Ktor\u0026#34;, \u0026#34;descricao\u0026#34;: \u0026#34;Completar tutorial\u0026#34;}\u0026#34;\u0026#34;\u0026#34;) } assertEquals(HttpStatusCode.Created, response.status) } O testApplication cria um ambiente de teste completo sem abrir portas de rede, tornando os testes rápidos e isolados.\nConclusão O Ktor é um framework poderoso que abraça a filosofia do Kotlin: conciso, seguro e explícito. Ele é perfeito para microserviços, APIs REST e aplicações onde você quer controle total sobre o que acontece. Combinado com coroutines para concorrência e kotlinx.serialization para JSON, você tem um stack moderno e performático para o backend.\nSe está começando com Kotlin no servidor, o Ktor é uma excelente porta de entrada — mais acessível que o Spring Boot e com uma experiência de desenvolvimento verdadeiramente Kotlin-first. Se quiser comparar com frameworks de outras linguagens, veja como Go lida com APIs usando Gin e Echo ou como Python aborda o problema com FastAPI e Django.\n","permalink":"https://kotlin.dev.br/blog/ktor-criando-apis-kotlin/","summary":"\u003cp\u003eSe você procura um framework leve, idiomático e 100% Kotlin para construir APIs REST, o Ktor é a escolha certa. Criado pela JetBrains (a mesma empresa por trás do Kotlin), o Ktor aproveita o melhor da linguagem: coroutines nativas, DSLs elegantes e tipagem forte. Neste tutorial, vamos construir uma API REST completa do zero.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-o-ktor\"\u003eO que é o Ktor?\u003c/h2\u003e\n\u003cp\u003eKtor é um framework assíncrono para criar aplicações conectadas — servidores HTTP, clientes HTTP, microserviços e WebSockets. Diferente do \u003ca href=\"/blog/kotlin-spring-boot/\"\u003eSpring Boot\u003c/a\u003e, que traz um ecossistema gigante de convenções e auto-configuração, o Ktor segue a filosofia de ser \u003cstrong\u003eminimalista e modular\u003c/strong\u003e: você adiciona apenas o que precisa, sem mágica escondida.\u003c/p\u003e","title":"Ktor: Criando APIs REST com Kotlin | Kotlin Brasil"},{"content":"As scope functions sao um dos recursos mais usados e, ao mesmo tempo, mais confusos de Kotlin. Existem cinco delas — let, run, with, apply e also — e todas fazem basicamente a mesma coisa: executam um bloco de codigo no contexto de um objeto. A diferença está nos detalhes: como o objeto é referenciado e o que a funcao retorna.\nNeste guia, vamos desmistificar cada uma com exemplos práticos do mundo real.\nO que são scope functions? Scope functions são funcoes da biblioteca padrão do Kotlin que criam um escopo temporário para um objeto. Dentro desse escopo, voce acessa o objeto sem precisar repetir seu nome. Elas existem para tornar o código mais conciso e legível — especialmente quando voce precisa fazer várias operacões em sequência sobre o mesmo objeto.\nTodas as cinco funcoes fazem essencialmente o mesmo: executam um bloco de código em um objeto. O que muda entre elas sao dois fatores:\nComo o objeto é referenciado: via this (receptor) ou it (argumento) O que é retornado: o resultado da lambda ou o próprio objeto Tabela comparativa Antes de mergulhar nos detalhes, aqui está o resumo que voce vai consultar sempre:\nFuncao Referência ao objeto Valor de retorno Caso de uso principal let it Resultado da lambda Transformacoes, null-safety run this Resultado da lambda Inicializacao + computacao with this Resultado da lambda Operacoes em bloco apply this Objeto contexto Configuracao de objetos also it Objeto contexto Efeitos colaterais Guarde essa tabela. A chave é entender que this permite chamar metodos diretamente (sem prefixo), enquanto it é um nome explícito para o objeto.\nlet: transformacao e null-safety A funcao let é provavelmente a scope function mais usada em Kotlin. Ela recebe o objeto como argumento (it) e retorna o resultado da lambda.\nO caso de uso classico é com o operador de chamada segura (?.):\nval nome: String? = obterNomeDoBanco() // Sem let — verboso if (nome != null) { val formatado = nome.trim().uppercase() println(formatado) } // Com let — idiomático nome?.let { val formatado = it.trim().uppercase() println(formatado) } O ?.let só executa o bloco se o valor não for nulo. E uma alternativa elegante ao if (x != null).\nOutro uso comum é para transformacoes em cadeia:\nval resultado = listaDePedidos .filter { it.status == Status.PENDENTE } .let { pedidosPendentes -\u0026gt; // Renomear \u0026#39;it\u0026#39; para clareza println(\u0026#34;Encontrados ${pedidosPendentes.size} pedidos pendentes\u0026#34;) pedidosPendentes.sortedBy { it.data } } Note que voce pode renomear it para um nome mais descritivo — algo que nao é possível com this.\nrun: inicializacao + computacao A funcao run é como o let, mas usa this em vez de it. Isso significa que voce pode chamar metodos do objeto diretamente, sem prefixo. Ela retorna o resultado da lambda.\nval resultado = servico.run { // \u0026#39;this\u0026#39; é o servico — chamadas diretas configurar(timeout = 5000) conectar() executarQuery(\u0026#34;SELECT * FROM usuarios\u0026#34;) } // resultado = retorno de executarQuery() O run tambem tem uma versao sem receptor, util para limitar escopo de variaveis:\nval hexColor = run { val r = (0..255).random() val g = (0..255).random() val b = (0..255).random() String.format(\u0026#34;#%02x%02x%02x\u0026#34;, r, g, b) } // r, g, b não vazam para o escopo externo Esse padrão é excelente para computacoes que precisam de variaveis temporárias sem poluir o escopo ao redor.\nwith: operacoes em bloco sem null-safety A funcao with é quase identica ao run, mas com uma diferença importante: ela não é uma extension function. Voce passa o objeto como argumento:\nval descricao = with(usuario) { // \u0026#39;this\u0026#39; é o usuario \u0026#34;Nome: $nome, Email: $email, Cidade: $cidade\u0026#34; } O with é ideal quando voce tem um objeto não-nulo e quer fazer várias operacoes nele:\nwith(canvas) { drawColor(Color.WHITE) drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint) drawText(\u0026#34;Kotlin\u0026#34;, 100f, 200f, textPaint) drawCircle(150f, 300f, 50f, circlePaint) } A limitacao do with é que ele não funciona com null-safety (?.). Se o objeto pode ser nulo, use run ou let no lugar.\napply: configuracao de objetos A funcao apply usa this como referência ao objeto, mas diferente do run, ela retorna o próprio objeto em vez do resultado da lambda. Isso a torna perfeita para configurar objetos no estilo builder:\nval requisicao = HttpRequest().apply { url = \u0026#34;https://api.exemplo.com/dados\u0026#34; method = \u0026#34;POST\u0026#34; headers[\u0026#34;Content-Type\u0026#34;] = \u0026#34;application/json\u0026#34; headers[\u0026#34;Authorization\u0026#34;] = \u0026#34;Bearer $token\u0026#34; timeout = 30_000 body = \u0026#34;\u0026#34;\u0026#34;{\u0026#34;chave\u0026#34;: \u0026#34;valor\u0026#34;}\u0026#34;\u0026#34;\u0026#34; } // requisicao é o HttpRequest configurado O apply é extremamente comum em código Android com Kotlin:\nval intent = Intent(context, DetalheActivity::class.java).apply { putExtra(\u0026#34;PRODUTO_ID\u0026#34;, produto.id) putExtra(\u0026#34;PRODUTO_NOME\u0026#34;, produto.nome) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } startActivity(intent) Sempre que voce precisar criar um objeto e configurar suas propriedades em sequência, apply é a escolha certa.\nalso: efeitos colaterais A funcao also é a contraparte do apply: ela retorna o próprio objeto, mas usa it em vez de this. Ela é ideal para efeitos colaterais — acoes que voce quer executar \u0026ldquo;de passagem\u0026rdquo; sem alterar a cadeia de operacoes:\nval usuario = criarUsuario(\u0026#34;Maria\u0026#34;) .also { println(\u0026#34;Usuario criado: ${it.nome}\u0026#34;) } .also { analytics.registrar(\u0026#34;novo_usuario\u0026#34;, it.id) } .also { validador.verificar(it) } O also é perfeito para logging e depuracao em cadeias de chamadas:\nval numeros = listOf(1, 5, 3, 2, 4) .also { println(\u0026#34;Original: $it\u0026#34;) } .sorted() .also { println(\u0026#34;Ordenado: $it\u0026#34;) } .reversed() .also { println(\u0026#34;Invertido: $it\u0026#34;) } Voce pode inserir chamadas also em qualquer ponto de uma cadeia para inspecionar valores intermediários — e removê-las depois sem afetar a lógica.\nQuando usar qual: arvore de decisao Na dúvida sobre qual scope function escolher, siga este fluxo:\nPrecisa tratar nulidade? Use ?.let { } Quer configurar propriedades de um objeto? Use apply Quer fazer efeitos colaterais (log, validacao)? Use also Quer computar algo usando metodos do objeto? Use run Tem um objeto não-nulo e quer operar nele em bloco? Use with Outra forma de pensar:\nPrecisa do resultado da lambda? let, run ou with Precisa do objeto de volta? apply ou also Quer chamar metodos direto (sem it.)? run, with ou apply Quer um nome explícito para o objeto? let ou also Erros comuns e anti-patterns As scope functions melhoram a legibilidade quando usadas com moderacao. Mas o abuso delas cria código mais difícil de ler do que o original.\nNesting excessivo — o erro mais comum:\n// RUIM — difícil de ler usuario?.let { u -\u0026gt; u.endereco?.let { e -\u0026gt; e.cidade?.let { c -\u0026gt; println(\u0026#34;Cidade: $c\u0026#34;) } } } // BOM — simples e direto val cidade = usuario?.endereco?.cidade if (cidade != null) { println(\u0026#34;Cidade: $cidade\u0026#34;) } Usar scope function sem necessidade:\n// RUIM — let desnecessário val tamanho = lista.let { it.size } // BOM — direto val tamanho = lista.size Misturar retornos: tenha cuidado com apply e run dentro da mesma cadeia — os retornos diferentes podem causar bugs sutis.\nA regra de ouro: se a scope function não torna o código mais claro, não use. Código explícito sempre vence código \u0026ldquo;esperto\u0026rdquo;.\nExemplos do mundo real Para consolidar, veja como as scope functions aparecem em código de produção:\nConfiguracao de cliente HTTP com apply:\nval client = OkHttpClient.Builder().apply { connectTimeout(30, TimeUnit.SECONDS) readTimeout(30, TimeUnit.SECONDS) addInterceptor(loggingInterceptor) if (BuildConfig.DEBUG) { addInterceptor(debugInterceptor) } }.build() Processamento de resposta com let:\nfun buscarUsuario(id: Int): UsuarioDTO? { return repositorio.findById(id)?.let { entidade -\u0026gt; UsuarioDTO( nome = entidade.nome, email = entidade.email, ativo = entidade.deletadoEm == null ) } } Logging condicional com also:\nfun processarPagamento(pedido: Pedido): Resultado { return gateway.cobrar(pedido.valor) .also { resultado -\u0026gt; if (resultado.sucesso) { logger.info(\u0026#34;Pagamento aprovado: ${pedido.id}\u0026#34;) } else { logger.warn(\u0026#34;Pagamento recusado: ${pedido.id} - ${resultado.motivo}\u0026#34;) } } } Conclusao As scope functions sao ferramentas poderosas que, quando bem usadas, tornam o código Kotlin mais conciso e expressivo. A chave é entender as duas dimensões: como o objeto é referenciado (this vs it) e o que é retornado (resultado da lambda vs objeto contexto).\nCom a prática, a escolha se torna intuitiva. Comece com let para null-safety, apply para configuracao de objetos e also para logging. Conforme ganhar confiança, incorpore run e with no seu repertório. E lembre-se: se o código fica mais confuso com scope function, é melhor sem ela.\nPara aprofundar seus conhecimentos na linguagem, confira nosso guia sobre o que é Kotlin e o tutorial de extension functions, que complementam perfeitamente o entendimento das scope functions. Se você programa em outras linguagens, é interessante comparar: Rust não tem scope functions, mas resolve encadeamento com pattern matching e closures, enquanto Python usa context managers (with) para um propósito similar.\n","permalink":"https://kotlin.dev.br/blog/scope-functions-kotlin/","summary":"\u003cp\u003eAs scope functions sao um dos recursos mais usados e, ao mesmo tempo, mais confusos de Kotlin. Existem cinco delas — \u003ccode\u003elet\u003c/code\u003e, \u003ccode\u003erun\u003c/code\u003e, \u003ccode\u003ewith\u003c/code\u003e, \u003ccode\u003eapply\u003c/code\u003e e \u003ccode\u003ealso\u003c/code\u003e — e todas fazem basicamente a mesma coisa: executam um bloco de codigo no contexto de um objeto. A diferença está nos detalhes: como o objeto é referenciado e o que a funcao retorna.\u003c/p\u003e\n\u003cp\u003eNeste guia, vamos desmistificar cada uma com exemplos práticos do mundo real.\u003c/p\u003e","title":"Scope Functions em Kotlin: Guia Completo | Kotlin Brasil"},{"content":"Sobre a vagaA GFT busca uma pessoa Desenvolvedora Java + Kotlin Sênior para atuação em modelo híbrido em Alphaville, São Paulo.\nResponsabilidadesDesenvolver e manter aplicações backend com Java, Kotlin e Spring.Trabalhar com integrações, mensageria e serviços em nuvem.Colaborar com times técnicos na entrega de soluções escaláveis e de alta qualidade.RequisitosExperiência sênior com Java e Kotlin.Conhecimento em Spring Boot e Spring Framework.Experiência com PostgreSQL e bancos NoSQL.Vivência com AWS, Kafka, Docker e Git.Conhecimento em Node.js será considerado relevante para o contexto da vaga.Modelo de trabalhoAtuação híbrida em Alphaville, São Paulo.\n","permalink":"https://kotlin.dev.br/vagas/lbu0prsnb4xslmlx-gft-desenvolvedor-java-kotlin-senior-hibrido/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA GFT busca uma pessoa Desenvolvedora Java + Kotlin Sênior para atuação em modelo híbrido em Alphaville, São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações backend com Java, Kotlin e Spring.\u003c/li\u003e\u003cli\u003eTrabalhar com integrações, mensageria e serviços em nuvem.\u003c/li\u003e\u003cli\u003eColaborar com times técnicos na entrega de soluções escaláveis e de alta qualidade.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com Java e Kotlin.\u003c/li\u003e\u003cli\u003eConhecimento em Spring Boot e Spring Framework.\u003c/li\u003e\u003cli\u003eExperiência com PostgreSQL e bancos NoSQL.\u003c/li\u003e\u003cli\u003eVivência com AWS, Kafka, Docker e Git.\u003c/li\u003e\u003cli\u003eConhecimento em Node.js será considerado relevante para o contexto da vaga.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eAtuação híbrida em Alphaville, São Paulo.\u003c/p\u003e","title":"Desenvolvedor Java + Kotlin Sênior (Híbrido)"},{"content":"Sobre a vagaO Banco PAN busca uma pessoa Engenheiro(a) de Software Sênior para atuar na área de IT Veículos, em modelo híbrido em São Paulo.\nResponsabilidadesDesenvolver e manter serviços backend com Java, Kotlin e Spring Boot.Atuar com APIs REST, integrações e soluções em ambientes distribuídos.Contribuir para pipelines de CI/CD e práticas de qualidade de código.Apoiar observabilidade, monitoramento e sustentação de aplicações em produção.RequisitosExperiência sênior em desenvolvimento backend com Java e Kotlin.Conhecimento em Spring Boot, REST, SQL e bancos NoSQL.Experiência com Docker, Kubernetes e ambientes AWS.Vivência com Git, GitHub Actions, Jenkins ou Azure DevOps.Conhecimento em ferramentas como SonarQube, Kibana, Dynatrace e Grafana.Experiência com MongoDB, Redis, DynamoDB, EKS, S3, IAM ou ElastiCache.Modelo de trabalhoVaga híbrida em São Paulo, São Paulo, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/iy4vjoabnb386p20-banco-pan-engenheiro-a-de-software-sr-java-kotlin/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO Banco PAN busca uma pessoa Engenheiro(a) de Software Sênior para atuar na área de IT Veículos, em modelo híbrido em São Paulo.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend com Java, Kotlin e Spring Boot.\u003c/li\u003e\u003cli\u003eAtuar com APIs REST, integrações e soluções em ambientes distribuídos.\u003c/li\u003e\u003cli\u003eContribuir para pipelines de CI/CD e práticas de qualidade de código.\u003c/li\u003e\u003cli\u003eApoiar observabilidade, monitoramento e sustentação de aplicações em produção.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento backend com Java e Kotlin.\u003c/li\u003e\u003cli\u003eConhecimento em Spring Boot, REST, SQL e bancos NoSQL.\u003c/li\u003e\u003cli\u003eExperiência com Docker, Kubernetes e ambientes AWS.\u003c/li\u003e\u003cli\u003eVivência com Git, GitHub Actions, Jenkins ou Azure DevOps.\u003c/li\u003e\u003cli\u003eConhecimento em ferramentas como SonarQube, Kibana, Dynatrace e Grafana.\u003c/li\u003e\u003cli\u003eExperiência com MongoDB, Redis, DynamoDB, EKS, S3, IAM ou ElastiCache.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eVaga híbrida em São Paulo, São Paulo, Brasil.\u003c/p\u003e","title":"Engenheiro(a) de Software Sr. Java/Kotlin"},{"content":"Salários de Desenvolvedor Kotlin no Brasil (2026) Se você está considerando aprender Kotlin ou quer saber se está sendo bem remunerado, este guia traz dados atualizados de 2026 sobre salários de desenvolvedores Kotlin no Brasil — do júnior ao staff engineer, passando por vagas remotas internacionais que pagam em dólar.\nKotlin deixou de ser apenas \u0026ldquo;a linguagem do Android\u0026rdquo;. Hoje, ela é usada em backends de alta performance com Ktor e Spring Boot, em projetos multiplataforma com Kotlin Multiplatform, e até em ciência de dados. Essa versatilidade impacta diretamente os salários: a demanda por profissionais Kotlin cresce mais rápido que a oferta, o que mantém a remuneração consistentemente acima da média do mercado brasileiro de tecnologia.\nNeste artigo, você vai encontrar tabelas detalhadas de salários por senioridade, comparações com outras linguagens como Java, Python, Go e Swift, as empresas que melhor remuneram, e estratégias concretas para aumentar seus ganhos.\nTabela de Salários por Senioridade (CLT e PJ) A tabela abaixo mostra as faixas salariais para desenvolvedores Kotlin no Brasil em 2026, considerando regime CLT e PJ. Os valores refletem dados de plataformas como Glassdoor, Levels.fyi, vagas publicadas em portais brasileiros e pesquisas salariais do mercado.\nRegime CLT Senioridade Faixa Salarial Mensal Média Observações Júnior (0-2 anos) R$ 4.000 – R$ 7.000 R$ 5.500 Entrada no mercado, foco em Android ou backend simples Pleno (2-5 anos) R$ 7.000 – R$ 12.000 R$ 9.500 Autonomia em projetos, domínio de frameworks Sênior (5-8 anos) R$ 12.000 – R$ 18.000 R$ 15.000 Liderança técnica, decisões arquiteturais Staff/Principal (8+ anos) R$ 18.000 – R$ 28.000+ R$ 22.000 Visão sistêmica, mentoria, influência organizacional Regime PJ Senioridade Faixa Salarial Mensal Média Júnior R$ 5.500 – R$ 9.000 R$ 7.000 Pleno R$ 9.000 – R$ 16.000 R$ 12.500 Sênior R$ 16.000 – R$ 25.000 R$ 20.000 Staff/Principal R$ 25.000 – R$ 40.000+ R$ 32.000 Nota sobre PJ vs CLT: No regime PJ, a remuneração bruta é tipicamente 30% a 50% maior que CLT para compensar a ausência de benefícios como FGTS, férias remuneradas e 13º salário. Ao comparar propostas, considere o custo total: plano de saúde, impostos PJ (Simples Nacional ~6-15%), e reserva para férias e 13º.\nVariação regional Os maiores salários se concentram em São Paulo, Campinas, Curitiba, Florianópolis e Belo Horizonte. Porém, com a consolidação do trabalho remoto pós-pandemia, a diferença regional vem diminuindo — empresas de SP contratam profissionais em qualquer estado pagando faixas competitivas.\nCapitais do Nordeste como Recife e Fortaleza têm cenas tech em crescimento, com salários cerca de 10-15% abaixo da média de SP, mas custo de vida proporcionalmente menor.\nSalários em Vagas Remotas Internacionais (USD) Trabalhar remotamente para empresas estrangeiras é a forma mais rápida de multiplicar seus ganhos como desenvolvedor Kotlin. Com o câmbio favorável, mesmo posições mid-level pagam significativamente mais que vagas sênior no mercado local.\nSenioridade Faixa Mensal (USD) Equivalente Aproximado (BRL)* Mid-level (2-5 anos) USD 4.000 – USD 7.000 R$ 22.000 – R$ 38.500 Senior (5-8 anos) USD 7.000 – USD 12.000 R$ 38.500 – R$ 66.000 Staff/Principal (8+ anos) USD 12.000 – USD 20.000+ R$ 66.000 – R$ 110.000+ *Considerando câmbio de R$ 5,50/USD. Valores podem variar.\nComo conseguir vagas remotas internacionais Inglês fluente é obrigatório — não apenas leitura, mas comunicação verbal em reuniões diárias e design reviews Perfil no LinkedIn em inglês — recrutadores internacionais buscam ativamente devs Kotlin no Brasil Contribuições open source — especialmente em projetos do ecossistema Kotlin/JetBrains Plataformas especializadas — Turing, Toptal, Arc.dev, Remote OK, We Work Remotely Networking — conferências como KotlinConf, comunidades no Slack e Discord Importante: Para receber em USD como PJ, considere abrir uma conta internacional (Wise, Payoneer, Husky) e consulte um contador sobre tributação de rendimentos do exterior.\nKotlin vs Outras Linguagens: Comparação Salarial Como Kotlin se compara com outras linguagens populares no mercado brasileiro? A tabela abaixo mostra as médias salariais para nível sênior (CLT) em 2026:\nLinguagem Salário Sênior CLT (Média) Demanda Tendência Kotlin R$ 15.000 🔥 Alta e crescente ↑ Subindo Java R$ 13.500 Alta (estável) → Estável Python R$ 14.000 🔥 Muito alta ↑ Subindo Go R$ 16.000 Média (crescente) ↑ Subindo rápido Swift R$ 14.500 Média → Estável Flutter/Dart R$ 12.000 Média → Estável TypeScript R$ 12.500 Muito alta → Estável Análise comparativa Kotlin vs Java: Desenvolvedores Kotlin ganham em média 10-20% mais que desenvolvedores Java no mesmo nível. Isso ocorre porque Kotlin é mais recente, tem menor pool de profissionais experientes, e é a linguagem preferida para novos projetos Android e backends modernos. Muitas empresas migram de Java para Kotlin e precisam de profissionais que dominem ambas. Confira nossa comparação detalhada Kotlin vs Java.\nKotlin vs Python: Python tem uma base de profissionais muito maior e atua em áreas diferentes (data science, ML, automação). Em backend web puro, Kotlin tende a pagar ligeiramente mais. Mas Python com especialização em ML/AI pode ultrapassar Kotlin nos níveis mais altos. Veja também os salários de Python no python.dev.br.\nKotlin vs Go: Go é a linguagem que mais compete com Kotlin em termos salariais no Brasil. Go paga ligeiramente mais em média, mas tem menos vagas totais. Ambas são excelentes escolhas para backend de alta performance.\nKotlin vs Swift: Enquanto Swift é exclusiva do ecossistema Apple, Kotlin domina o Android e, com Kotlin Multiplatform, avança para iOS também. Kotlin tem mais vagas no Brasil pelo domínio do Android no mercado mobile brasileiro (80%+ de market share).\nKotlin vs Flutter/Dart: Flutter é popular para apps multiplataforma, mas Kotlin nativo mantém vantagem salarial por oferecer melhor performance e acesso completo às APIs nativas do Android.\nEmpresas que Pagam Bem para Desenvolvedores Kotlin Empresas brasileiras As fintechs e scale-ups brasileiras estão entre as que melhor remuneram desenvolvedores Kotlin:\nEmpresa Faixa Sênior (CLT) Stack Kotlin Destaque Nubank R$ 18.000 – R$ 28.000 Android, Backend Maior fintech da América Latina, stock options PicPay R$ 15.000 – R$ 22.000 Android, Backend Forte cultura de engenharia Itaú R$ 16.000 – R$ 24.000 Android, Backend Spring PLR agressivo, estabilidade BTG Pactual R$ 18.000 – R$ 30.000 Backend, Android Maior banco de investimentos digital Stone R$ 14.000 – R$ 20.000 Android, Backend Pagamentos e maquininhas iFood R$ 15.000 – R$ 23.000 Android, Backend Super app brasileiro Mercado Livre R$ 16.000 – R$ 25.000 Android, Backend E-commerce líder na LATAM C6 Bank R$ 14.000 – R$ 21.000 Android Banco digital em expansão Muitas dessas empresas oferecem benefícios adicionais significativos: stock options/RSUs, bônus por performance (até 3-5 salários), plano de saúde premium, auxílio home office, e orçamento para educação.\nEmpresas internacionais (vagas remotas) Estas empresas contratam desenvolvedores Kotlin no Brasil para trabalho remoto:\nEmpresa Faixa Sênior (USD/mês) Foco Kotlin Destaque Google USD 8.000 – USD 18.000 Android, Multiplatform Criadora do Android, forte em Kotlin JetBrains USD 6.000 – USD 14.000 Tooling, IDE, Compiler Criadora do Kotlin Netflix USD 10.000 – USD 20.000+ Android, Backend Remuneração top of market Uber USD 8.000 – USD 16.000 Android, Backend Escala massiva Square (Block) USD 7.000 – USD 15.000 Android, Backend Pioneira em Kotlin para Android Amazon USD 7.000 – USD 14.000 Android, Backend AWS + apps, stock options Spotify USD 7.000 – USD 13.000 Android Forte em UX mobile Dica: A JetBrains, criadora do Kotlin, é uma das empresas mais desejadas por devs Kotlin. Além de salários competitivos, você trabalha diretamente na evolução da linguagem.\nComo Aumentar Seu Salário como Desenvolvedor Kotlin Se você quer sair da faixa atual e alcançar os salários mais altos do mercado, estas são as estratégias com maior retorno comprovado:\n1. Especialize-se em áreas de alta demanda Nem todas as especializações pagam igual. Estas são as que mais valorizam seu salário em 2026:\nAndroid com Jetpack Compose (+15-25%)\nCompose é o futuro do desenvolvimento Android nativo Empresas migram de XML para Compose e precisam de profissionais experientes Domine LazyColumn, State management, e testes de UI Confira nosso tutorial de Jetpack Compose Backend com Ktor (+20-30%)\nKtor é o framework web Kotlin da JetBrains, ganhando tração rápida Ideal para microserviços de alta performance Profissionais que dominam Ktor + Coroutines são raros e valorizados Veja o guia completo de Ktor Kotlin Multiplatform (KMP) (+25-40%)\nA especialização mais rara e mais bem paga do ecossistema Kotlin Permite compartilhar código entre Android, iOS, web e desktop Adoção crescente em empresas como Netflix, Philips, e Cash App Explore nosso tutorial de Kotlin Multiplatform Spring Boot com Kotlin (+10-15%)\nA combinação mais comum no mercado enterprise brasileiro Grande demanda em bancos, fintechs e consultorias Kotlin é totalmente interoperável com o ecossistema Spring/Java Confira o tutorial de Spring Boot com Kotlin 2. Invista em inglês fluente O inglês é o maior multiplicador salarial para desenvolvedores brasileiros. A diferença entre trabalhar para uma empresa brasileira e uma empresa internacional pode ser de 3x a 5x no salário.\nPratique conversação técnica diariamente (design reviews, stand-ups) Leia documentação e blogs técnicos em inglês Participe de comunidades internacionais de Kotlin Considere um curso focado em inglês para devs 3. Contribua para open source Contribuições para projetos open source em Kotlin demonstram competência real e aumentam sua visibilidade:\nKotlin stdlib — contribuições para a biblioteca padrão Ktor — framework web da JetBrains Compose Multiplatform — UI toolkit multiplataforma KotlinX libraries — serialization, coroutines, datetime Arrow-kt — programação funcional em Kotlin Um perfil GitHub ativo com contribuições relevantes pode ser o diferencial em processos seletivos para vagas que pagam 30-50% acima da média.\n4. Certificações e formação contínua Embora o mercado de tecnologia valorize mais experiência prática que diplomas, algumas certificações têm peso:\nGoogle Associate Android Developer — valida competência em desenvolvimento Android com Kotlin Spring Professional Certification — reconhecida no mercado enterprise AWS/GCP/Azure certifications — complementam o perfil backend Confira nosso guia completo sobre certificações Kotlin.\n5. Desenvolva soft skills de liderança Para alcançar os níveis Staff e Principal (R$18k-28k+ CLT, R$25k-40k+ PJ), habilidades técnicas não bastam. Você precisa de:\nComunicação clara — documentar decisões, apresentar trade-offs Mentoria — elevar o nível técnico do time Visão sistêmica — entender o impacto de decisões técnicas no negócio Influência sem autoridade — liderar iniciativas técnicas transversais Mercado de Trabalho Kotlin em 2026: Panorama O mercado de Kotlin no Brasil está em um momento particularmente favorável para profissionais qualificados:\nFatores que impulsionam a demanda Android continua dominante — com 80%+ de market share no Brasil, e Kotlin como linguagem oficial desde 2019, a demanda é contínua Adoção crescente no backend — empresas que já usam Kotlin no mobile estão adotando no backend (Ktor, Spring Boot) para manter uma stack unificada Kotlin Multiplatform amadureceu — KMP saiu de experimental para estável, abrindo um mercado inteiramente novo Fintechs em expansão — o setor financeiro brasileiro é um dos maiores empregadores de devs Kotlin Migração de Java para Kotlin — grandes empresas como Itaú e Bradesco migram seus sistemas, criando demanda por profissionais que dominam ambas Projeção para os próximos anos A tendência é de crescimento sustentado nos salários de Kotlin, impulsionado por:\nMenor oferta de profissionais experientes comparado com Java e JavaScript Expansão do KMP reduzindo a necessidade de times separados iOS/Android Aumento das contratações remotas internacionais por empresas americanas e europeias Acompanhe as vagas disponíveis na nossa seção de vagas Kotlin.\nPerguntas Relacionadas Para mais informações sobre carreira e mercado de trabalho Kotlin, explore estes conteúdos:\nSalário de Desenvolvedor Kotlin Júnior Salário de Desenvolvedor Kotlin Pleno Salário de Desenvolvedor Kotlin Sênior Como se Tornar Desenvolvedor Kotlin Roadmap de Desenvolvedor Android Roadmap de Desenvolvedor Backend Kotlin Kotlin no Mercado de Trabalho Vagas Kotlin no Brasil Vagas Kotlin Remoto Glossário de Termos Kotlin Fontes e Metodologia Disclaimer: Os dados salariais apresentados neste artigo são baseados em pesquisas de mercado, vagas publicadas em portais como Glassdoor, Levels.fyi, LinkedIn, Gupy, e dados de comunidades de desenvolvedores brasileiros. As faixas salariais representam estimativas e podem variar significativamente com base em localização, porte da empresa, benefícios oferecidos, e negociação individual. Este conteúdo não constitui aconselhamento de carreira profissional. Valores de vagas internacionais em USD consideram câmbio aproximado e podem variar.\nAs informações são atualizadas periodicamente. Última atualização: março de 2026.\nQuer comparar com outras linguagens? Veja os salários de Go no golang.com.br e Python no python.dev.br.\n","permalink":"https://kotlin.dev.br/carreira/salarios-kotlin-brasil/","summary":"\u003ch1 id=\"salários-de-desenvolvedor-kotlin-no-brasil-2026\"\u003eSalários de Desenvolvedor Kotlin no Brasil (2026)\u003c/h1\u003e\n\u003cp\u003eSe você está considerando aprender Kotlin ou quer saber se está sendo bem remunerado, este guia traz \u003cstrong\u003edados atualizados de 2026\u003c/strong\u003e sobre salários de desenvolvedores Kotlin no Brasil — do júnior ao staff engineer, passando por vagas remotas internacionais que pagam em dólar.\u003c/p\u003e\n\u003cp\u003eKotlin deixou de ser apenas \u0026ldquo;a linguagem do Android\u0026rdquo;. Hoje, ela é usada em backends de alta performance com \u003ca href=\"/glossario/ktor/\"\u003eKtor\u003c/a\u003e e \u003ca href=\"/glossario/spring-boot/\"\u003eSpring Boot\u003c/a\u003e, em projetos multiplataforma com \u003ca href=\"/glossario/kotlin-multiplatform/\"\u003eKotlin Multiplatform\u003c/a\u003e, e até em ciência de dados. Essa versatilidade impacta diretamente os salários: \u003cstrong\u003ea demanda por profissionais Kotlin cresce mais rápido que a oferta\u003c/strong\u003e, o que mantém a remuneração consistentemente acima da média do mercado brasileiro de tecnologia.\u003c/p\u003e","title":"Salários Kotlin no Brasil 2026: De R$4k a R$90k/mês"},{"content":"Sobre a vagaA TRACTIAN busca uma pessoa Engenheiro(a) de QA de Software de nível pleno para atuar remotamente, com base em São Paulo, São Paulo, Brasil.\nStack e ferramentasAutomação de testes com Cypress, Playwright, Selenium, Appium, Maestro, Espresso, XCUITest, Rest Assured e Robot Framework.Linguagens e plataformas: Kotlin, TypeScript, JavaScript e Swift.Integração contínua com GitHub Actions, GitLab CI e Jenkins.ResponsabilidadesPlanejar, implementar e manter testes automatizados para aplicações web, mobile e APIs.Apoiar a qualidade do software ao longo do ciclo de desenvolvimento.Colaborar com times de engenharia para identificar falhas, melhorar cobertura de testes e apoiar entregas mais confiáveis.RequisitosExperiência de nível pleno em Quality Assurance ou automação de testes.Vivência com ferramentas de testes automatizados e pipelines de CI/CD.Conhecimento em Kotlin ou em linguagens usadas no ecossistema de testes da vaga. ","permalink":"https://kotlin.dev.br/vagas/mwelkbbtaxbtzgtd-tractian-engenheiro-a-de-qa-de-software/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA TRACTIAN busca uma pessoa Engenheiro(a) de QA de Software de nível pleno para atuar remotamente, com base em São Paulo, São Paulo, Brasil.\u003c/p\u003e\u003ch3\u003eStack e ferramentas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eAutomação de testes com Cypress, Playwright, Selenium, Appium, Maestro, Espresso, XCUITest, Rest Assured e Robot Framework.\u003c/li\u003e\u003cli\u003eLinguagens e plataformas: Kotlin, TypeScript, JavaScript e Swift.\u003c/li\u003e\u003cli\u003eIntegração contínua com GitHub Actions, GitLab CI e Jenkins.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003ePlanejar, implementar e manter testes automatizados para aplicações web, mobile e APIs.\u003c/li\u003e\u003cli\u003eApoiar a qualidade do software ao longo do ciclo de desenvolvimento.\u003c/li\u003e\u003cli\u003eColaborar com times de engenharia para identificar falhas, melhorar cobertura de testes e apoiar entregas mais confiáveis.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência de nível pleno em Quality Assurance ou automação de testes.\u003c/li\u003e\u003cli\u003eVivência com ferramentas de testes automatizados e pipelines de CI/CD.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin ou em linguagens usadas no ecossistema de testes da vaga.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro(a) de QA de Software"},{"content":"Neste tutorial, você vai aprender as boas práticas mais importantes ao escrever código Kotlin. Vamos cobrir convenções de nomenclatura, formatação, padrões idiomáticos e ferramentas de análise estática como ktlint e detekt. Seguir essas práticas torna o código mais legivel, mais fácil de manter e alinhado com o que a comunidade Kotlin espera. Se você já conhece o básico da linguagem — variaveis e tipos, funções e classes — esta pronto para dar esse proximo passo.\nConvenções de Nomenclatura A primeira coisa que qualquer pessoa percebe ao ler código alheio são os nomes. Kotlin segue convenções muito parecidas com as do Java, mas com algumas particularidades.\nPacotes devem usar letras minusculas e sem underscores:\n// Bom package com.meuapp.dominio.usuario // Ruim package com.meuApp.Dominio.Usuario Classes e interfaces usam PascalCase. Nomes de data classes seguem a mesma regra:\n// Bom class ContaBancaria data class Endereco(val rua: String, val numero: Int) interface Repositorio // Ruim class conta_bancaria data class endereco(val rua: String, val numero: Int) Funções, propriedades e variaveis locais usam camelCase:\n// Bom fun calcularDesconto(valor: Double): Double { ... } val nomeCompleto = \u0026#34;Maria Silva\u0026#34; // Ruim fun CalcularDesconto(valor: Double): Double { ... } val nome_completo = \u0026#34;Maria Silva\u0026#34; Constantes (propriedades const val ou valores em companion objects que são verdadeiramente constantes) usam SCREAMING_SNAKE_CASE:\ncompanion object { const val TAXA_MAXIMA = 0.15 const val TEMPO_LIMITE_MS = 5000L } Uma dica que vale ouro: evite abreviacoes obscuras. Prefira quantidadeDeItens a qtdItens. O código e lido muito mais vezes do que e escrito, entao investir em nomes claros economiza tempo de todo mundo.\nFormatação e Ferramentas de Análise Manter um estilo consistente em todo o projeto e fundamental, especialmente quando há mais de uma pessoa contribuindo. Duas ferramentas se destacam no ecossistema Kotlin.\nktlint O ktlint e um linter e formatador que aplica as convenções oficiais de estilo do Kotlin. Ele pode ser adicionado ao projeto via Gradle:\n// build.gradle.kts plugins { id(\u0026#34;org.jlleitschuh.gradle.ktlint\u0026#34;) version \u0026#34;12.1.0\u0026#34; } Com isso, você pode rodar ./gradlew ktlintCheck para verificar o estilo e ./gradlew ktlintFormat para corrigir automaticamente. O ideal e integrar isso ao pipeline de CI para que nenhum código fora do padrão entre no repositório.\ndetekt Enquanto o ktlint cuida da formatação, o detekt vai além e faz análise estática de qualidade. Ele detecta code smells como funções muito longas, complexidade ciclomatica alta, magic numbers e muito mais.\n// build.gradle.kts plugins { id(\u0026#34;io.gitlab.arturbosch.detekt\u0026#34;) version \u0026#34;1.23.4\u0026#34; } detekt { config.setFrom(\u0026#34;$projectDir/config/detekt/detekt.yml\u0026#34;) buildUponDefaultConfig = true } Usar as duas ferramentas juntas garante que o código esta tanto bem formatado quanto saudavel em termos de qualidade.\nPrefira when no Lugar de Cadeias de if-else Uma das marcas registradas do Kotlin idiomatico e o uso de expressoes when no lugar de longas cadeias de if-else. Alem de ser mais legivel, o when funciona como expressao, ou seja, retorna um valor.\n// Ruim: cadeia de if-else fun classificarNota(nota: Int): String { if (nota \u0026gt;= 9) { return \u0026#34;Excelente\u0026#34; } else if (nota \u0026gt;= 7) { return \u0026#34;Bom\u0026#34; } else if (nota \u0026gt;= 5) { return \u0026#34;Regular\u0026#34; } else { return \u0026#34;Insuficiente\u0026#34; } } // Bom: when como expressao fun classificarNota(nota: Int): String = when { nota \u0026gt;= 9 -\u0026gt; \u0026#34;Excelente\u0026#34; nota \u0026gt;= 7 -\u0026gt; \u0026#34;Bom\u0026#34; nota \u0026gt;= 5 -\u0026gt; \u0026#34;Regular\u0026#34; else -\u0026gt; \u0026#34;Insuficiente\u0026#34; } Quando você combina when com sealed classes, o compilador garante que todos os casos foram tratados, eliminando a necessidade do bloco else e protegendo contra esquecimentos.\nUse Data Classes para Dados Se uma classe existe primariamente para armazenar dados, ela deve ser uma data class. O compilador gera automaticamente equals(), hashCode(), toString(), copy() e funções de destructuring, eliminando código boilerplate.\n// Ruim: classe regular para dados class Usuario(val nome: String, val email: String) { override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is Usuario) return false return nome == other.nome \u0026amp;\u0026amp; email == other.email } override fun hashCode(): Int = 31 * nome.hashCode() + email.hashCode() override fun toString(): String = \u0026#34;Usuario(nome=$nome, email=$email)\u0026#34; } // Bom: data class data class Usuario(val nome: String, val email: String) A versão com data class faz exatamente a mesma coisa que a versão manual, só que em uma única linha. Menos código significa menos bugs.\nScope Functions: use com Criterio Kotlin oferece cinco scope functions — let, run, with, apply e also. Cada uma tem seu caso de uso ideal, e a chave e não exagerar. Se você quer se aprofundar, veja o tutorial de lambdas.\n// Bom: let para null check val comprimento = nome?.let { println(\u0026#34;Processando: $it\u0026#34;) it.length } // Bom: apply para configurar objetos val textView = TextView(context).apply { text = \u0026#34;Ola, mundo\u0026#34; textSize = 16f setTextColor(Color.BLACK) } // Ruim: aninhar scope functions desnecessariamente val resultado = valor?.let { v -\u0026gt; v.toString().let { s -\u0026gt; s.uppercase().also { u -\u0026gt; println(u) } } } A regra de bolso e: se o aninhamento dificulta a leitura, quebre em variaveis intermediarias. Legibilidade sempre vem primeiro.\nEvite Tipos Nullable Desnecessarios O sistema de null safety do Kotlin e uma das suas maiores vantagens. Porem, muita gente vinda do Java acaba usando ? em tudo por habito. Pergunte-se sempre: essa propriedade realmente pode ser nula?\n// Ruim: nullable sem necessidade class Pedido( val id: Long?, val descricao: String?, val valor: Double? ) // Bom: so nullable quando faz sentido class Pedido( val id: Long, val descricao: String, val valor: Double, val cupomDesconto: String? = null // este sim pode ser nulo ) Quanto menos tipos nullable no seu código, menos verificacoes de nulo você precisa fazer e menor a chance de NullPointerException em tempo de execução.\nPrefira Imutabilidade com val Sempre que possível, use val em vez de var. Propriedades imutáveis são mais faceis de entender, mais seguras em contextos concorrentes é fácilitam o raciocinio sobre o estado do programa.\n// Ruim: var quando nao precisa mudar var nome = \u0026#34;Kotlin Brasil\u0026#34; // Bom: val quando o valor nao muda val nome = \u0026#34;Kotlin Brasil\u0026#34; O mesmo vale para collections. Prefira listOf() e mapOf() (imutáveis) e só use mutableListOf() quando realmente precisar modificar a colecao.\n// Bom: colecao imutavel val linguagens = listOf(\u0026#34;Kotlin\u0026#34;, \u0026#34;Java\u0026#34;, \u0026#34;Scala\u0026#34;) // So quando necessario val resultados = mutableListOf\u0026lt;String\u0026gt;() resultados.add(\u0026#34;Primeiro resultado\u0026#34;) Sealed Classes para Modelar Estado Quando você precisa representar um conjunto finito de estados — como o resultado de uma chamada de rede ou o estado de uma tela — sealed classes são a escolha ideal.\nsealed class UiState\u0026lt;out T\u0026gt; { object Carregando : UiState\u0026lt;Nothing\u0026gt;() data class Sucesso\u0026lt;T\u0026gt;(val dados: T) : UiState\u0026lt;T\u0026gt;() data class Erro(val mensagem: String) : UiState\u0026lt;Nothing\u0026gt;() } // Uso no ViewModel fun buscarUsuarios(): UiState\u0026lt;List\u0026lt;Usuario\u0026gt;\u0026gt; { return try { val usuarios = repositorio.buscarTodos() UiState.Sucesso(usuarios) } catch (e: Exception) { UiState.Erro(e.message ?: \u0026#34;Erro desconhecido\u0026#34;) } } // Tratamento exaustivo na UI when (val estado = viewModel.estado) { is UiState.Carregando -\u0026gt; mostrarLoading() is UiState.Sucesso -\u0026gt; mostrarLista(estado.dados) is UiState.Erro -\u0026gt; mostrarErro(estado.mensagem) } Essa abordagem e amplamente usada em projetos com MVVM e Jetpack Compose, e deixa o fluxo de dados muito mais previsivel.\nOutras Boas Práticas Rápidas Antes de encerrar, vale listar mais algumas práticas que fazem diferenca no dia a dia:\nUse string templates: prefira \u0026quot;Ola, $nome\u0026quot; em vez de \u0026quot;Ola, \u0026quot; + nome. Use named arguments em funções com muitos parametros: criarUsuario(nome = \u0026quot;Ana\u0026quot;, idade = 28) e muito mais claro do que criarUsuario(\u0026quot;Ana\u0026quot;, 28). Use default parameters em vez de sobrecargas de função: fun conectar( host: String, porta: Int = 8080, usarSsl: Boolean = true ) { ... } Prefira extension functions para adicionar comportamento a classes existentes em vez de criar classes utilitarias com métodos estaticos. Escreva testes desde o inicio. Código bem escrito e código testavel. Conclusão Boas práticas não são regras rigidas gravadas em pedra — são diretrizes que evoluem com a comunidade e com a própria linguagem. O mais importante e manter consistencia dentro do projeto e priorizar a legibilidade. Ferramentas como ktlint e detekt ajudam a automatizar parte desse trabalho, mas o bom senso do desenvolvedor continua sendo insubstituivel.\nSe você esta comecando agora com Kotlin, não tente aplicar todas essas práticas de uma vez. Va incorporando aos poucos, comecando pelas mais basicas como nomenclatura e uso de val, e depois avance para padrões mais sofisticados como sealed classes e scope functions. Com o tempo, escrever código Kotlin idiomatico vai se tornar natural.\n","permalink":"https://kotlin.dev.br/tutoriais/boas-praticas-kotlin/","summary":"\u003cp\u003eNeste tutorial, você vai aprender as \u003cstrong\u003eboas práticas mais importantes ao escrever código Kotlin\u003c/strong\u003e. Vamos cobrir convenções de nomenclatura, formatação, padrões idiomáticos e ferramentas de análise estática como ktlint e detekt. Seguir essas práticas torna o código mais legivel, mais fácil de manter e alinhado com o que a comunidade Kotlin espera. Se você já conhece o básico da linguagem — \u003ca href=\"/tutoriais/variaveis-e-tipos/\"\u003evariaveis e tipos\u003c/a\u003e, \u003ca href=\"/tutoriais/fun%C3%A7%C3%B5es-kotlin/\"\u003efunções\u003c/a\u003e e \u003ca href=\"/tutoriais/classes-e-objetos-kotlin/\"\u003eclasses\u003c/a\u003e — esta pronto para dar esse proximo passo.\u003c/p\u003e","title":"Boas Práticas em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Neste tutorial, você vai aprender tudo sobre delegação de propriedades em Kotlin — um recurso elegante que permite reutilizar lógica de acesso a propriedades sem repetir código. Vamos explorar a palavra-chave by, os delegates da standard library como lazy, observable e vetoable, delegação via Map e como criar seus próprios delegates customizados. Se você já conhece classes e objetos e lambdas, esta pronto para esse topico.\nO que é Delegação de Propriedades? Em Kotlin, uma propriedade normalmente armazena seu valor em um campo (backing field). Mas as vezes você precisa de comportamento extra toda vez que o valor e lido ou escrito — logar a mudanca, validar o novo valor, calcular sob demanda, buscar de um cache e por aí vai.\nVocê poderia escrever getters e setters customizados, mas se essa mesma lógica se repete em várias propriedades ou classes, o código fica duplicado. A delegação de propriedades resolve esse problema: você delega o armazenamento é o acesso da propriedade para outro objeto usando a palavra-chave by.\nclass Exemplo { var texto: String by MeuDelegate() } Quando alguem lê exemplo.texto, o Kotlin chama o método getValue() do delegate. Quando alguem escreve exemplo.texto = \u0026quot;novo\u0026quot;, o Kotlin chama setValue(). O objeto delegate encapsula toda a lógica.\nlazy: Inicialização Preguicosa O delegate mais usado do Kotlin e provavelmente o lazy. Ele adia a inicialização de uma propriedade até o momento em que ela e acessada pela primeira vez. Depois disso, o valor calculado fica em cache e e retornado diretamente nas leituras seguintes.\nclass ConfiguracaoApp { val dadosPesados: List\u0026lt;String\u0026gt; by lazy { println(\u0026#34;Carregando dados... (so acontece uma vez)\u0026#34;) carregarDoBancoDeDados() } private fun carregarDoBancoDeDados(): List\u0026lt;String\u0026gt; { // Simula uma operacao custosa return listOf(\u0026#34;config1\u0026#34;, \u0026#34;config2\u0026#34;, \u0026#34;config3\u0026#34;) } } fun main() { val config = ConfiguracaoApp() println(\u0026#34;Objeto criado, dados ainda nao carregados\u0026#34;) println(config.dadosPesados) // Aqui o bloco lazy e executado println(config.dadosPesados) // Aqui usa o cache } Por padrão, lazy e thread-safe (usa LazyThreadSafetyMode.SYNCHRONIZED). Se você sabe que a propriedade sera acessada apenas por uma thread, pode usar lazy(LazyThreadSafetyMode.NONE) para evitar o custo de sincronizacao:\nval valor: String by lazy(LazyThreadSafetyMode.NONE) { \u0026#34;Inicializado sem sincronizacao\u0026#34; } O lazy só funciona com val, já que o valor e calculado uma única vez e nunca muda depois disso. Para cenários onde você precisa de inicialização tardia com var, considere usar lateinit.\nobservable: Reagindo a Mudancas O delegate Delegates.observable() permite executar um callback toda vez que o valor de uma propriedade muda. E muito útil para atualizar a interface, logar mudancas ou notificar outros componentes.\nimport kotlin.properties.Delegates class Carrinho { var quantidadeItens: Int by Delegates.observable(0) { propriedade, valorAntigo, valorNovo -\u0026gt; println(\u0026#34;${propriedade.name} mudou de $valorAntigo para $valorNovo\u0026#34;) atualizarBadge(valorNovo) } private fun atualizarBadge(quantidade: Int) { println(\u0026#34;Badge atualizado: $quantidade itens\u0026#34;) } } fun main() { val carrinho = Carrinho() carrinho.quantidadeItens = 3 // Imprime a mudanca e atualiza o badge carrinho.quantidadeItens = 7 // Idem } O callback recebe tres parametros: a referência a propriedade (KProperty), o valor antigo e o valor novo. Importante: o callback e chamado depois que o valor já foi atribuido.\nvetoable: Validando Antes de Atribuir Se você precisa validar um valor antes de aceita-lo, use Delegates.vetoable(). O callback retorna true para aceitar a mudanca ou false para rejeita-la, mantendo o valor anterior.\nimport kotlin.properties.Delegates class Conta { var saldo: Double by Delegates.vetoable(0.0) { _, valorAntigo, valorNovo -\u0026gt; if (valorNovo \u0026lt; 0) { println(\u0026#34;Operação negada: saldo nao pode ser negativo (tentou: $valorNovo)\u0026#34;) false } else { println(\u0026#34;Saldo atualizado: $valorAntigo -\u0026gt; $valorNovo\u0026#34;) true } } } fun main() { val conta = Conta() conta.saldo = 1000.0 // Aceito conta.saldo = 500.0 // Aceito conta.saldo = -200.0 // Rejeitado, saldo continua 500.0 println(\u0026#34;Saldo final: ${conta.saldo}\u0026#34;) // 500.0 } Esse padrão e particularmente útil para propriedades que representam configurações ou limites que não devem ultrapassar certos valores.\nDelegação por Map Um caso de uso muito prático e delegar propriedades para um Map. Isso e especialmente útil ao trabalhar com dados dinâmicos, como JSON parseado ou configurações carregadas de um arquivo.\nclass Usuario(dados: Map\u0026lt;String, Any?\u0026gt;) { val nome: String by dados val email: String by dados val idade: Int by dados } fun main() { val mapa = mapOf( \u0026#34;nome\u0026#34; to \u0026#34;Carlos Oliveira\u0026#34;, \u0026#34;email\u0026#34; to \u0026#34;carlos@email.com\u0026#34;, \u0026#34;idade\u0026#34; to 32 ) val usuario = Usuario(mapa) println(\u0026#34;${usuario.nome}, ${usuario.email}, ${usuario.idade}\u0026#34;) // Carlos Oliveira, carlos@email.com, 32 } O Kotlin usa o nome da propriedade como chave no mapa. Para propriedades mutaveis (var), basta usar MutableMap:\nclass Configuração(dados: MutableMap\u0026lt;String, Any?\u0026gt;) { var tema: String by dados var fontSize: Int by dados } fun main() { val dados = mutableMapOf\u0026lt;String, Any?\u0026gt;( \u0026#34;tema\u0026#34; to \u0026#34;escuro\u0026#34;, \u0026#34;fontSize\u0026#34; to 14 ) val config = Configuração(dados) config.tema = \u0026#34;claro\u0026#34; println(dados[\u0026#34;tema\u0026#34;]) // \u0026#34;claro\u0026#34; — o mapa e atualizado } Esse padrão e uma alternativa elegante ao uso de data classes quando a estrutura dos dados não e conhecida em tempo de compilação.\nCriando Delegates Customizados Para criar seu próprio delegate, você precisa implementar as interfaces ReadOnlyProperty (para val) ou ReadWriteProperty (para var):\nimport kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty class TrimDelegate : ReadWriteProperty\u0026lt;Any?, String\u0026gt; { private var valor: String = \u0026#34;\u0026#34; override fun getValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;): String { return valor } override fun setValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;, value: String) { valor = value.trim() } } class Formulario { var nome: String by TrimDelegate() var email: String by TrimDelegate() } fun main() { val form = Formulario() form.nome = \u0026#34; Maria Silva \u0026#34; form.email = \u0026#34; maria@email.com \u0026#34; println(\u0026#34;\u0026#39;${form.nome}\u0026#39;\u0026#34;) // \u0026#39;Maria Silva\u0026#39; println(\u0026#34;\u0026#39;${form.email}\u0026#39;\u0026#34;) // \u0026#39;maria@email.com\u0026#39; } O TrimDelegate automaticamente remove espacos em branco das pontas toda vez que um valor e atribuido. Esse tipo de lógica reutilizavel e o ponto forte da delegação.\nCaso Prático: SharedPreferences Delegate No desenvolvimento Android, um dos usos mais elegantes de delegates customizados e encapsular o acesso a SharedPreferences. Em vez de repetir chamadas getString(), putString() e afins espalhadas pelo código, você cria um delegate que faz isso transparentemente.\nimport android.content.SharedPreferences import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty class StringPreference( private val prefs: SharedPreferences, private val chave: String, private val valorPadrao: String = \u0026#34;\u0026#34; ) : ReadWriteProperty\u0026lt;Any?, String\u0026gt; { override fun getValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;): String { return prefs.getString(chave, valorPadrao) ?: valorPadrao } override fun setValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;, value: String) { prefs.edit().putString(chave, value).apply() } } // Função auxiliar para facilitar o uso fun SharedPreferences.string(chave: String, padrao: String = \u0026#34;\u0026#34;) = StringPreference(this, chave, padrao) // Uso class Preferencias(prefs: SharedPreferences) { var nomeUsuario: String by prefs.string(\u0026#34;nome_usuario\u0026#34;) var tema: String by prefs.string(\u0026#34;tema\u0026#34;, \u0026#34;escuro\u0026#34;) var idioma: String by prefs.string(\u0026#34;idioma\u0026#34;, \u0026#34;pt-BR\u0026#34;) } Repare como a extension function string() torna a declaracao das propriedades extremamente limpa. Quem usa a classe Preferencias nem precisa saber que por tras dos panos os dados estao sendo persistidos em SharedPreferences.\nCaso Prático: Delegate com Log para ViewModel Outro cenário comum e criar um delegate que loga todas as mudancas de estado em um ViewModel:\nimport kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty class LoggedProperty\u0026lt;T\u0026gt;( private var valor: T, private val tag: String = \u0026#34;ViewModel\u0026#34; ) : ReadWriteProperty\u0026lt;Any?, T\u0026gt; { override fun getValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;): T = valor override fun setValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;, value: T) { println(\u0026#34;[$tag] ${property.name}: $valor -\u0026gt; $value\u0026#34;) valor = value } } fun \u0026lt;T\u0026gt; logged(valorInicial: T, tag: String = \u0026#34;ViewModel\u0026#34;) = LoggedProperty(valorInicial, tag) // Uso class PedidoViewModel { var status: String by logged(\u0026#34;pendente\u0026#34;, \u0026#34;PedidoVM\u0026#34;) var total: Double by logged(0.0, \u0026#34;PedidoVM\u0026#34;) } fun main() { val vm = PedidoViewModel() vm.status = \u0026#34;processando\u0026#34; // [PedidoVM] status: pendente -\u0026gt; processando vm.total = 149.90 // [PedidoVM] total: 0.0 -\u0026gt; 149.90 } Esse tipo de delegate e muito útil durante o desenvolvimento para rastrear mudancas de estado sem poluir a lógica de negocios com chamadas de log.\nCombinando Delegates Uma técnica avançada e combinar delegates. Por exemplo, uma propriedade que e lazy na primeira leitura mas observable nas escritas subsequentes. Embora a standard library não oferca isso diretamente, você pode implementar o comportamento que precisar criando seu próprio delegate:\nclass LazyObservable\u0026lt;T\u0026gt;( private val inicializador: () -\u0026gt; T, private val onChange: (antigo: T, novo: T) -\u0026gt; Unit ) : ReadWriteProperty\u0026lt;Any?, T\u0026gt; { private var valor: T? = null private var inicializado = false override fun getValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;): T { if (!inicializado) { valor = inicializador() inicializado = true } @Suppress(\u0026#34;UNCHECKED_CAST\u0026#34;) return valor as T } override fun setValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;, value: T) { val antigo = if (inicializado) valor as T else inicializador() valor = value inicializado = true onChange(antigo, value) } } Quando Usar Delegação de Propriedades A delegação de propriedades brilha nos seguintes cenários:\nInicialização preguicosa: quando calcular o valor inicial e custoso e pode não ser necessário. Use lazy. Observacao de mudancas: quando outros componentes precisam ser notificados. Use observable. Validação: quando valores precisam ser verificados antes da atribuicao. Use vetoable. Persistencia transparente: SharedPreferences, banco de dados ou cache sem poluir o código de negocios. Dados dinâmicos: quando a estrutura vem de um mapa ou JSON. Use delegação por Map. Evite usar delegates em excesso ou para lógica trivial. Se um getter ou setter simples resolve, não há necessidade de abstrair com delegação. Como em tudo no desenvolvimento de software, o bom senso e a melhor ferramenta.\nConclusão A delegação de propriedades e um dos recursos mais elegantes do Kotlin e exemplifica bem a filosofia da linguagem de reduzir boilerplate sem sacrificar clareza. Com lazy, observable, vetoable e delegates customizados, você consegue encapsular comportamentos complexos de forma reutilizavel e transparente.\nSe você quer se aprofundar em padrões de delegação de forma mais ampla — incluindo delegação de classes com by — consulte a entrada sobre delegation no glossario. E para ver delegates em acao dentro de arquiteturas reais, confira o tutorial sobre MVVM, onde delegates como lazy e observables são amplamente utilizados.\n","permalink":"https://kotlin.dev.br/tutoriais/delegacao-propriedades/","summary":"\u003cp\u003eNeste tutorial, você vai aprender tudo sobre \u003cstrong\u003edelegação de propriedades em Kotlin\u003c/strong\u003e — um recurso elegante que permite reutilizar lógica de acesso a propriedades sem repetir código. Vamos explorar a palavra-chave \u003ccode\u003eby\u003c/code\u003e, os delegates da standard library como \u003ccode\u003elazy\u003c/code\u003e, \u003ccode\u003eobservable\u003c/code\u003e e \u003ccode\u003evetoable\u003c/code\u003e, delegação via Map e como criar seus próprios delegates customizados. Se você já conhece \u003ca href=\"/tutoriais/classes-e-objetos-kotlin/\"\u003eclasses e objetos\u003c/a\u003e e \u003ca href=\"/tutoriais/lambdas-kotlin/\"\u003elambdas\u003c/a\u003e, esta pronto para esse topico.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-delegação-de-propriedades\"\u003eO que é Delegação de Propriedades?\u003c/h2\u003e\n\u003cp\u003eEm Kotlin, uma propriedade normalmente armazena seu valor em um campo (backing field). Mas as vezes você precisa de comportamento extra toda vez que o valor e lido ou escrito — logar a mudanca, validar o novo valor, calcular sob demanda, buscar de um cache e por aí vai.\u003c/p\u003e","title":"Delegação de Propriedades em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Sobre a vagaA Platform Science busca uma pessoa Engenheira de Software Pleno para atuação presencial em Londrina, Paraná. A vaga envolve desenvolvimento de software com Kotlin, Java, Spring Boot e tecnologias web.\nResponsabilidadesDesenvolver, manter e evoluir aplicações usando Kotlin, Java e Spring Boot.Trabalhar em interfaces e integrações com Angular ou React.Colaborar com testes automatizados, pipelines de CI/CD e boas práticas de engenharia.Atuar com bancos de dados, mensageria, observabilidade e ambientes cloud.RequisitosExperiência em desenvolvimento de software em nível pleno.Conhecimento em Java, Kotlin e Spring Boot.Experiência com Angular ou React.Vivência com testes usando JUnit, Jasmine ou Jest.Conhecimento em PostgreSQL, MySQL ou MongoDB.Experiência com mensageria, como Kafka, RabbitMQ ou SQS.Familiaridade com AWS, Azure ou Google Cloud.Conhecimento em CI/CD com GitHub Actions, Jenkins, Buildkite ou Bamboo.DiferenciaisExperiência com Netty.Conhecimento em Terraform.Vivência com observabilidade usando Grafana e Prometheus. ","permalink":"https://kotlin.dev.br/vagas/weep11jxtaw6xsae-platform-science-engenheiro-de-software-pleno/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Platform Science busca uma pessoa Engenheira de Software Pleno para atuação presencial em Londrina, Paraná. A vaga envolve desenvolvimento de software com Kotlin, Java, Spring Boot e tecnologias web.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver, manter e evoluir aplicações usando Kotlin, Java e Spring Boot.\u003c/li\u003e\u003cli\u003eTrabalhar em interfaces e integrações com Angular ou React.\u003c/li\u003e\u003cli\u003eColaborar com testes automatizados, pipelines de CI/CD e boas práticas de engenharia.\u003c/li\u003e\u003cli\u003eAtuar com bancos de dados, mensageria, observabilidade e ambientes cloud.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento de software em nível pleno.\u003c/li\u003e\u003cli\u003eConhecimento em Java, Kotlin e Spring Boot.\u003c/li\u003e\u003cli\u003eExperiência com Angular ou React.\u003c/li\u003e\u003cli\u003eVivência com testes usando JUnit, Jasmine ou Jest.\u003c/li\u003e\u003cli\u003eConhecimento em PostgreSQL, MySQL ou MongoDB.\u003c/li\u003e\u003cli\u003eExperiência com mensageria, como Kafka, RabbitMQ ou SQS.\u003c/li\u003e\u003cli\u003eFamiliaridade com AWS, Azure ou Google Cloud.\u003c/li\u003e\u003cli\u003eConhecimento em CI/CD com GitHub Actions, Jenkins, Buildkite ou Bamboo.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com Netty.\u003c/li\u003e\u003cli\u003eConhecimento em Terraform.\u003c/li\u003e\u003cli\u003eVivência com observabilidade usando Grafana e Prometheus.\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Software Pleno"},{"content":"Kotlin no server-side deixou de ser novidade faz tempo. Grandes empresas como JetBrains, Google, Amazon e diversas fintechs brasileiras já rodam Kotlin em producao no backend. A questao hoje não é mais \u0026ldquo;devo usar Kotlin no servidor?\u0026rdquo;, mas sim \u0026ldquo;qual framework escolher?\u0026rdquo;. Neste guia, vamos comparar os cinco frameworks mais relevantes do ecossistema \u0026ndash; Ktor, Spring Boot, Quarkus, Micronaut e http4k \u0026ndash; com exemplos de código, tabela comparativa e recomendações para diferentes cenários.\nVisao Geral do Ecossistema O ecossistema server-side Kotlin amadureceu bastante nos ultimos anos. Você tem opções que vao desde frameworks opinados e cheios de bateria incluida (como Spring Boot) até frameworks minimalistas onde você monta tudo no braco (como http4k). A escolha depende de fatores como tamanho da equipe, requisitos de performance, familiaridade do time e necessidade de integração com bibliotecas existentes.\nAntes de entrarmos nos detalhes de cada framework, vale mencionar que todos eles se beneficiam das coroutines do Kotlin para lidar com concorrência de forma eficiente. Se você ainda não domina coroutines, o guia completo de coroutines é um excelente ponto de partida.\nKtor Ktor é o framework web criado pela JetBrains, a mesma empresa por tras do Kotlin. Ele e assíncrono por natureza, baseado em coroutines, e segue uma filosofia modular onde você instala apenas os plugins que precisa. Se quiser partir direto para código, abra o tutorial de Ktor com Exposed e construa uma API REST com banco de dados passo a passo.\nimport io.ktor.server.application.* import io.ktor.server.engine.* import io.ktor.server.netty.* import io.ktor.server.response.* import io.ktor.server.routing.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.Serializable @Serializable data class Produto(val id: Long, val nome: String, val preco: Double) fun main() { embeddedServer(Netty, port = 8080) { install(ContentNegotiation) { json() } routing { get(\u0026#34;/\u0026#34;) { call.respondText(\u0026#34;Kotlin Brasil API\u0026#34;) } route(\u0026#34;/produtos\u0026#34;) { get { val produtos = listOf( Produto(1, \u0026#34;Teclado Mecanico\u0026#34;, 450.0), Produto(2, \u0026#34;Mouse Gamer\u0026#34;, 220.0) ) call.respond(produtos) } get(\u0026#34;/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toLongOrNull() if (id != null) { call.respond(Produto(id, \u0026#34;Produto #$id\u0026#34;, 99.90)) } else { call.respondText(\u0026#34;ID invalido\u0026#34;, status = io.ktor.http.HttpStatusCode.BadRequest) } } } } }.start(wait = true) } O Ktor usa uma DSL idiomatica do Kotlin para definir rotas, o que torna o código muito legivel. A serialização com kotlinx.serialization e nativa e não depende de reflection, o que beneficia tanto a performance quanto a compatibilidade com Kotlin Multiplatform. Para se aprofundar no Ktor, confira o guia dedicado de Ktor.\nPontos fortes do Ktor Criado pela JetBrains, integração perfeita com Kotlin Assíncrono nativamente via coroutines Leve e modular: você adiciona só o que precisa Compativel com Kotlin Multiplatform Suporta Netty, Jetty, CIO e Tomcat como engines Pontos de atencao Ecossistema de plugins menor que Spring Curva de aprendizado para quem vem de frameworks opinados Menos material em português disponivel Spring Boot Spring Boot dispensa apresentações. E o framework mais popular da JVM, com suporte oficial e maduro ao Kotlin. A equipe do Spring investiu pesado na experiência com Kotlin, incluindo extension functions, suporte a coroutines no WebFlux e null-safety integrada.\nimport org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication import org.springframework.web.bind.annotation.* data class Tarefa(val id: Long, val titulo: String, val concluida: Boolean) @RestController @RequestMapping(\u0026#34;/tarefas\u0026#34;) class TarefaController { private val tarefas = mutableListOf( Tarefa(1, \u0026#34;Estudar Kotlin\u0026#34;, false), Tarefa(2, \u0026#34;Configurar CI/CD\u0026#34;, true), Tarefa(3, \u0026#34;Escrever testes\u0026#34;, false) ) @GetMapping fun listar(): List\u0026lt;Tarefa\u0026gt; = tarefas @GetMapping(\u0026#34;/{id}\u0026#34;) fun buscar(@PathVariable id: Long): Tarefa? = tarefas.find { it.id == id } @PostMapping fun criar(@RequestBody tarefa: Tarefa): Tarefa { tarefas.add(tarefa) return tarefa } @DeleteMapping(\u0026#34;/{id}\u0026#34;) fun remover(@PathVariable id: Long) { tarefas.removeIf { it.id == id } } } @SpringBootApplication class Application fun main(args: Array\u0026lt;String\u0026gt;) { runApplication\u0026lt;Application\u0026gt;(*args) } Se sua equipe já conhece Spring, a transicao para Kotlin e quase transparente. O Spring reconhece as particularidades do Kotlin automaticamente, como a ausência de open por padrão (resolvida pelo plugin kotlin-spring) e o suporte a data classes como DTOs. Para um guia detalhado sobre Spring Boot com Kotlin, veja o guia de Spring Boot.\nPontos fortes do Spring Boot Ecossistema gigantesco com milhares de bibliotecas e starters Comunidade massiva, muito material e suporte Integração com praticamente qualquer tecnologia da JVM Spring WebFlux com suporte nativo a coroutines Ferramentas maduras de monitoramento, segurança e deployment Pontos de atencao Startup mais lento devido ao uso intenso de reflection Consumo de memória maior em comparação com frameworks mais leves Pode ser excessivo para microsserviços simples http4k O http4k segue uma abordagem radicalmente diferente. O conceito central e que servidores e clientes HTTP são apenas funções. Um servidor e uma função (Request) -\u0026gt; Response e pronto. Sem anotações, sem magica, sem reflection.\nimport org.http4k.core.* import org.http4k.core.Method.GET import org.http4k.core.Method.POST import org.http4k.core.Status.Companion.OK import org.http4k.core.Status.Companion.NOT_FOUND import org.http4k.format.Jackson.auto import org.http4k.routing.bind import org.http4k.routing.routes import org.http4k.server.Netty import org.http4k.server.asServer data class Mensagem(val texto: String, val autor: String) fun main() { val mensagemLens = Body.auto\u0026lt;Mensagem\u0026gt;().toLens() val mensagensLens = Body.auto\u0026lt;List\u0026lt;Mensagem\u0026gt;\u0026gt;().toLens() val mensagens = mutableListOf( Mensagem(\u0026#34;Kotlin e demais!\u0026#34;, \u0026#34;Ana\u0026#34;), Mensagem(\u0026#34;http4k e pura funcao\u0026#34;, \u0026#34;Bruno\u0026#34;) ) val app: HttpHandler = routes( \u0026#34;/mensagens\u0026#34; bind GET to { mensagensLens(mensagens, Response(OK)) }, \u0026#34;/mensagens\u0026#34; bind POST to { request -\u0026gt; val novaMensagem = mensagemLens(request) mensagens.add(novaMensagem) mensagensLens(mensagens, Response(OK)) }, \u0026#34;/saude\u0026#34; bind GET to { Response(OK).body(\u0026#34;OK\u0026#34;) } ) // Testar sem subir servidor -- e so uma funcao! val resposta = app(Request(GET, \u0026#34;/saude\u0026#34;)) println(resposta.bodyString()) // OK // Subir o servidor app.asServer(Netty(9000)).start() println(\u0026#34;Servidor rodando na porta 9000\u0026#34;) } A beleza do http4k esta na testabilidade. Como tudo e função, você pode testar seus endpoints chamando a função diretamente, sem precisar subir um servidor ou usar mocks complexos. O conceito de Lens (lente) para serialização pode parecer estranho no inicio, mas e extremamente seguro em termos de tipagem.\nPontos fortes do http4k Zero reflection, zero magica, zero anotações Testabilidade excepcional \u0026ndash; tudo e função pura Muito leve e rápido de iniciar Abordagem funcional alinhada com programação funcional Ideal para quem quer controle total Pontos de atencao Comunidade menor que Spring e Ktor Curva de aprendizado para o conceito de Lenses Menos integração pronta com ORMs e ferramentas enterprise Quarkus Quarkus e o framework da Red Hat projetado para ambientes cloud-native e containers. Ele faz processamento em tempo de compilação para reduzir drasticamente o tempo de startup e o consumo de memória, e oferece suporte a compilação nativa via GraalVM.\nO suporte a Kotlin no Quarkus e oficial e bem mantido. Você escreve endpoints de forma similar ao Spring (usando JAX-RS ou RESTEasy Reactive), mas com as otimizações de compilação do Quarkus.\nPontos fortes do Quarkus Startup extremamente rápido (milissegundos com GraalVM) Baixo consumo de memória, ideal para containers e serverless Dev mode com hot reload instantaneo Ecossistema robusto de extensoes Suporte a compilação nativa Pontos de atencao Kotlin e suportado mas não e a linguagem principal (Java tem prioridade) Compilação nativa com Kotlin pode apresentar incompatibilidades Menor presenca na comunidade Kotlin especificamente Micronaut Micronaut, criado pela equipe do Grails (Object Computing), também aposta em processamento em tempo de compilação para eliminar a reflection em runtime. Ele gera código de injeção de dependência, proxies e configurações durante a compilação, resultando em startup rápido e baixo consumo de memória.\nPontos fortes do Micronaut Injeção de dependência em tempo de compilação Startup rápido, comparavel ao Quarkus Suporte nativo a Kotlin com coroutines Boa documentação e tooling Integração com GraalVM para compilação nativa Pontos de atencao Ecossistema menor que Spring Debug de erros de compilação pode ser mais complexo Comunidade menor no Brasil Tabela Comparativa Caracteristica Ktor Spring Boot http4k Quarkus Micronaut Criador JetBrains VMware/Broadcom Comunidade Red Hat Object Computing Abordagem DSL modular Opinado, convencao Funcional pura Cloud-native Compilação AOT Coroutines Nativo WebFlux Via extensao Parcial Nativo Startup Rapido Lento Muito rápido Muito rápido Muito rápido Consumo memória Baixo Alto Muito baixo Muito baixo Baixo GraalVM nativo Experimental Via Spring Native Sim Sim Sim Ecossistema Medio Enorme Pequeno Grande Medio Curva aprendizado Media Baixa (se já sabe Spring) Media-Alta Media Media Kotlin-first Sim Nao (mas excelente suporte) Sim Nao Nao Multiplatform Sim Nao Nao Nao Nao Quando Usar Qual Escolher um framework não e questao de qual e \u0026ldquo;melhor\u0026rdquo;, e sim de qual se encaixa no seu contexto. Aqui vao recomendações práticas baseadas em cenários reais:\nEscolha Ktor quando:\nVocê quer uma experiência Kotlin-first sem fricao O projeto e um microservico ou API relativamente simples Você precisa de suporte a Kotlin Multiplatform A equipe valoriza controle fino sobre as dependências Escolha Spring Boot quando:\nA equipe já tem experiência com o ecossistema Spring O projeto precisa de integração com muitas tecnologias enterprise (JPA, Spring Security, mensageria) Você quer a maior quantidade de material de referência e suporte comunitario O custo de memória e startup não e uma restricao crítica Escolha http4k quando:\nVocê valoriza testabilidade acima de tudo A equipe tem afinidade com programação funcional O projeto precisa de um framework sem magica e sem surpresas Você quer controle total sobre o que acontece no seu código Escolha Quarkus quando:\nO deploy sera em ambiente serverless ou containers com limites apertados de recursos Tempo de startup e um requisito crítico Você precisa de compilação nativa via GraalVM A equipe tem familiaridade com JAX-RS Escolha Micronaut quando:\nVocê quer os beneficios de compilação AOT com uma experiência similar ao Spring O projeto envolve microsserviços que precisam ser leves Você quer injeção de dependência sem reflection em runtime Performance e Benchmarks Comparações de performance devem ser interpretadas com cautela, pois dependem fortemente do caso de uso, da configuração e do hardware. Dito isso, alguns padrões gerais se repetem consistentemente nos benchmarks da comunidade:\nEm termos de tempo de startup, http4k e Ktor lideram, com inicialização em poucos milissegundos. Quarkus e Micronaut ficam próximos quando usam compilação nativa. Spring Boot e consistentemente o mais lento para iniciar, tipicamente levando alguns segundos.\nEm throughput de requisicoes (requests por segundo), as diferenças são menores do que muita gente imagina. Spring WebFlux com coroutines, Ktor com Netty e http4k com Netty entregam números competitivos em cenários de alta concorrência. A diferenca real aparece no consumo de memória sob carga.\nEm consumo de memória, http4k e Ktor se destacam com footprints na casa de dezenas de MB. Spring Boot tipicamente consome de 200 a 400 MB. Quarkus e Micronaut nativos ficam abaixo de 50 MB.\nConstruindo Microsserviços em Kotlin Independentemente do framework escolhido, alguns padrões se aplicam a qualquer projeto server-side Kotlin. A injeção de dependência e fundamental para manter o código testavel. Uma boa arquitetura limpa ajuda a isolar o dominio das dependências externas. E a containerizacao com Docker e praticamente obrigatória para deployments modernos.\nSe você esta comecando um projeto novo e tem liberdade de escolha, minha sugestao e: comece com Ktor se o projeto for um microservico focado, ou com Spring Boot se você precisa de um ecossistema completo e a equipe já tem experiência. Teste http4k se a sua equipe curte a abordagem funcional. E avalie Quarkus ou Micronaut se o ambiente de execução impoe restricoes severas de recursos.\nConclusão O ecossistema server-side Kotlin esta maduro e diversificado. Nao existe bala de prata \u0026ndash; cada framework tem seus meritos e suas limitações. O importante e que Kotlin se provou uma linguagem excelente para o backend, oferecendo null-safety, coroutines, extension functions e uma expressividade que torna o código mais seguro e agradavel de escrever e manter. Para casos que exigem latência mínima e consumo zero de memória, Rust é uma alternativa a considerar. Já Go se destaca em microsserviços leves e ferramentas de infraestrutura. Seja qual for o framework que você escolher, o Kotlin no servidor e uma aposta segura para o longo prazo.\n","permalink":"https://kotlin.dev.br/guias/kotlin-server-side/","summary":"\u003cp\u003eKotlin no server-side deixou de ser novidade faz tempo. Grandes empresas como JetBrains, Google, Amazon e diversas fintechs brasileiras já rodam Kotlin em producao no backend. A questao hoje não é mais \u0026ldquo;devo usar Kotlin no servidor?\u0026rdquo;, mas sim \u0026ldquo;qual framework escolher?\u0026rdquo;. Neste guia, vamos comparar os cinco frameworks mais relevantes do ecossistema \u0026ndash; Ktor, Spring Boot, Quarkus, Micronaut e http4k \u0026ndash; com exemplos de código, tabela comparativa e recomendações para diferentes cenários.\u003c/p\u003e","title":"Frameworks Server-Side Kotlin: Guia Completo em Português | Kotlin Brasil"},{"content":"Kotlin Flow é a API de streams reativos da biblioteca de coroutines do Kotlin. Se você já trabalhou com RxJava, vai achar a API do Flow muito mais enxuta e natural, pois ela se integra diretamente com suspend functions e structured concurrency. Neste guia, vamos cobrir desde os fundamentos até padrões avançados de uso no Android e no backend, sempre com exemplos práticos que você pode adaptar aos seus projetos.\nO Que é um Flow Um Flow é uma sequência de valores emitidos de forma assíncrona. Diferente de uma Sequence, que e sincrona, o Flow permite que cada emissao envolva operações suspensas, como chamadas de rede ou consultas a banco de dados. A grande sacada e que o Flow e cold por padrão \u0026ndash; o código produtor só executa quando alguem começa a coletar.\nimport kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking import kotlinx.coroutines.delay fun contagem(): Flow\u0026lt;Int\u0026gt; = flow { for (i in 1..5) { delay(500) emit(i) } } fun main() = runBlocking { contagem().collect { valor -\u0026gt; println(\u0026#34;Recebido: $valor\u0026#34;) } } // Saida (com 500ms entre cada): // Recebido: 1 // Recebido: 2 // Recebido: 3 // Recebido: 4 // Recebido: 5 O builder flow { } define o bloco produtor. A função emit envia cada valor para quem estiver coletando. Sem a chamada a collect, nada acontece \u0026ndash; e justamente isso que caracteriza um cold flow.\nFlow Builders Alem do builder flow { }, existem outras formas de criar flows:\nimport kotlinx.coroutines.flow.* fun main() { // flowOf: cria um flow a partir de valores fixos val fixo: Flow\u0026lt;String\u0026gt; = flowOf(\u0026#34;Kotlin\u0026#34;, \u0026#34;Brasil\u0026#34;, \u0026#34;Flow\u0026#34;) // asFlow: converte coleções e sequencias em flow val deListagem: Flow\u0026lt;Int\u0026gt; = listOf(1, 2, 3).asFlow() val deRange: Flow\u0026lt;Int\u0026gt; = (1..10).asFlow() // channelFlow: quando voce precisa emitir de contextos diferentes val concorrente = channelFlow { send(\u0026#34;do contexto principal\u0026#34;) kotlinx.coroutines.launch { send(\u0026#34;de outra coroutine\u0026#34;) } } } O channelFlow e especialmente útil quando você precisa emitir valores a partir de múltiplas coroutines concorrentes, algo que o builder flow { } não permite diretamente por questões de segurança de thread.\nCold vs Hot Flows Essa distincao e fundamental para usar Flow corretamente. Um cold flow só começa a produzir valores quando alguem coleta. Cada coletor recebe sua própria execução independente do produtor. Ja um hot flow emite valores independentemente de ter coletores ou não.\nimport kotlinx.coroutines.* import kotlinx.coroutines.flow.* fun main() = runBlocking { // Cold Flow: cada collect dispara o produtor do zero val cold = flow { println(\u0026#34;Produtor iniciado\u0026#34;) emit(1) emit(2) } println(\u0026#34;--- Primeiro collect ---\u0026#34;) cold.collect { println(it) } println(\u0026#34;--- Segundo collect ---\u0026#34;) cold.collect { println(it) } // \u0026#34;Produtor iniciado\u0026#34; aparece duas vezes } Na prática, você usa cold flows para operações que precisam ser executadas por demanda, como buscar dados de uma API. Ja hot flows são ideais para representar estados que existem independentemente de quem observa, como o estado de uma tela no Android.\nOperadores de Transformacao Flow oferece um conjunto rico de operadores que permitem criar pipelines de processamento poderosos. A maioria segue a mesma lógica das funções de coleções do Kotlin:\nimport kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking data class Usuario(val nome: String, val idade: Int) fun main() = runBlocking { val usuarios = flowOf( Usuario(\u0026#34;Ana\u0026#34;, 28), Usuario(\u0026#34;Bruno\u0026#34;, 17), Usuario(\u0026#34;Carla\u0026#34;, 35), Usuario(\u0026#34;Diego\u0026#34;, 22), Usuario(\u0026#34;Elena\u0026#34;, 15) ) // map: transforma cada elemento usuarios .map { it.nome.uppercase() } .collect { println(it) } // ANA, BRUNO, CARLA, DIEGO, ELENA // filter: filtra elementos usuarios .filter { it.idade \u0026gt;= 18 } .collect { println(\u0026#34;${it.nome} e maior de idade\u0026#34;) } // transform: mais flexivel que map, permite emitir zero ou mais elementos usuarios .transform { usuario -\u0026gt; emit(\u0026#34;Processando: ${usuario.nome}\u0026#34;) if (usuario.idade \u0026gt;= 18) { emit(\u0026#34;${usuario.nome} aprovado\u0026#34;) } } .collect { println(it) } // take: limita a quantidade de elementos usuarios .take(3) .collect { println(it.nome) } // Ana, Bruno, Carla } O operador transform e o mais flexivel de todos. Enquanto map obrigatoriamente transforma um valor em outro, transform permite emitir quantos valores quiser para cada elemento de entrada, inclusive nenhum.\nCombinando Flows Em cenários reais, você frequentemente precisa combinar dados de múltiplas fontes. Flow oferece vários operadores para isso:\nimport kotlinx.coroutines.* import kotlinx.coroutines.flow.* fun main() = runBlocking { val nomes = flowOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;, \u0026#34;Carla\u0026#34;) val idades = flowOf(28, 33, 25) // zip: combina flows par a par nomes.zip(idades) { nome, idade -\u0026gt; \u0026#34;$nome tem $idade anos\u0026#34; }.collect { println(it) } // Ana tem 28 anos // Bruno tem 33 anos // Carla tem 25 anos // combine: emite sempre que qualquer flow emitir val temperatura = flow { emit(22) delay(1000) emit(25) delay(1000) emit(23) } val umidade = flow { emit(60) delay(1500) emit(55) } temperatura.combine(umidade) { temp, umi -\u0026gt; \u0026#34;Temp: ${temp}C, Umidade: ${umi}%\u0026#34; }.collect { println(it) } // merge: intercala emissoes de múltiplos flows val flow1 = flow { emit(\u0026#34;A1\u0026#34;); delay(100); emit(\u0026#34;A2\u0026#34;) } val flow2 = flow { emit(\u0026#34;B1\u0026#34;); delay(150); emit(\u0026#34;B2\u0026#34;) } merge(flow1, flow2).collect { println(it) } } A diferenca entre zip e combine e sutil mas importante: zip espera que ambos os flows emitam para produzir um par, enquanto combine re-emite sempre que qualquer um dos flows produz um novo valor, usando o ultimo valor do outro. No Android, combine e muito usado para combinar diferentes fontes de estado da UI.\nStateFlow e SharedFlow StateFlow e SharedFlow são as versões hot do Flow. Eles vivem no escopo de quem os cria e emitem valores independentemente dos coletores.\nimport kotlinx.coroutines.* import kotlinx.coroutines.flow.* class ContadorViewModel { // StateFlow: sempre tem um valor atual, ideal para estado de UI private val _contador = MutableStateFlow(0) val contador: StateFlow\u0026lt;Int\u0026gt; = _contador.asStateFlow() // SharedFlow: para eventos unicos, sem valor inicial obrigatorio private val _eventos = MutableSharedFlow\u0026lt;String\u0026gt;() val eventos: SharedFlow\u0026lt;String\u0026gt; = _eventos.asSharedFlow() fun incrementar() { _contador.value++ } suspend fun notificar(mensagem: String) { _eventos.emit(mensagem) } } fun main() = runBlocking { val viewModel = ContadorViewModel() // StateFlow emite o valor atual imediatamente ao coletar val job = launch { viewModel.contador.collect { println(\u0026#34;Contador: $it\u0026#34;) } } delay(100) viewModel.incrementar() delay(100) viewModel.incrementar() delay(100) job.cancel() // Saida: Contador: 0, Contador: 1, Contador: 2 } O StateFlow e a escolha padrão para representar estados no ViewModel de uma arquitetura MVVM. Ele sempre possui um valor (não pode ser vazio) e aplica distinctUntilChanged automaticamente, evitando emissoes duplicadas. Ja o SharedFlow e mais adequado para eventos pontuais como navegação ou mensagens de erro. Para entender melhor a arquitetura MVVM, veja o guia de MVVM com Kotlin.\ncallbackFlow Quando você precisa converter uma API baseada em callbacks para Flow, o callbackFlow e a ferramenta certa:\nimport kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.callbackFlow interface SensorListener { fun onDadoRecebido(valor: Float) fun onErro(erro: Throwable) } class SensorManager { private var listener: SensorListener? = null fun registrar(l: SensorListener) { listener = l } fun desregistrar() { listener = null } } fun SensorManager.dadosFlow() = callbackFlow { val listener = object : SensorListener { override fun onDadoRecebido(valor: Float) { trySend(valor) } override fun onErro(erro: Throwable) { close(erro) } } registrar(listener) awaitClose { desregistrar() } } O awaitClose e obrigatório e define o que acontece quando o flow e cancelado. Sem ele, o compilador emite um aviso. Esse padrão e muito comum ao integrar SDKs do Android como Firebase, sensores do dispositivo ou APIs de localização.\nBuffer e Conflate Quando o produtor e mais rápido que o consumidor, você pode usar buffer para desacoplar as velocidades ou conflate para descartar valores intermediarios:\nimport kotlinx.coroutines.* import kotlinx.coroutines.flow.* import kotlin.system.measureTimeMillis fun main() = runBlocking { val tempo = measureTimeMillis { flow { for (i in 1..5) { delay(100) // produz a cada 100ms emit(i) } } .buffer() // desacopla produtor e consumidor .collect { valor -\u0026gt; delay(300) // consome em 300ms println(valor) } } println(\u0026#34;Buffer levou ${tempo}ms\u0026#34;) // Sem buffer: ~2000ms / Com buffer: ~1700ms val tempoConflate = measureTimeMillis { flow { for (i in 1..5) { delay(100) emit(i) } } .conflate() // descarta valores intermediarios .collect { valor -\u0026gt; delay(300) println(valor) } } println(\u0026#34;Conflate levou ${tempoConflate}ms\u0026#34;) // Conflate pula valores intermediarios, processando apenas os mais recentes } A escolha entre buffer e conflate depende do cenário. Use buffer quando cada valor importa (como mensagens de chat). Use conflate quando apenas o valor mais recente importa (como atualizações de posicao GPS).\nTratamento de Erros Flow oferece operadores específicos para lidar com erros de forma declarativa:\nimport kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking fun main() = runBlocking { // catch: intercepta excecoes do upstream flow { emit(1) emit(2) throw RuntimeException(\u0026#34;Erro no produtor\u0026#34;) emit(3) // nunca executado } .catch { e -\u0026gt; println(\u0026#34;Capturado: ${e.message}\u0026#34;) } .collect { println(\u0026#34;Valor: $it\u0026#34;) } // Valor: 1 // Valor: 2 // Capturado: Erro no produtor // retry: tenta novamente em caso de falha var tentativa = 0 flow { tentativa++ if (tentativa \u0026lt; 3) throw RuntimeException(\u0026#34;Falha na tentativa $tentativa\u0026#34;) emit(\u0026#34;Sucesso na tentativa $tentativa\u0026#34;) } .retry(retries = 3) { causa -\u0026gt; println(\u0026#34;Retentando: ${causa.message}\u0026#34;) true } .collect { println(it) } // onCompletion: executa ao final, com ou sem erro flowOf(1, 2, 3) .onCompletion { causa -\u0026gt; if (causa == null) println(\u0026#34;Completou sem erros\u0026#34;) else println(\u0026#34;Completou com erro: ${causa.message}\u0026#34;) } .collect { println(it) } } O operador catch só captura exceções que ocorrem acima dele na cadeia (upstream). Erros no collect não são capturados por catch. Para um tratamento completo, considere usar onEach + launchIn ou um bloco try-catch ao redor do collect.\nTestando Flows Testar flows e direto ao ponto com as ferramentas certas. A biblioteca kotlinx-coroutines-test oferece o runTest e o Turbine e uma alternativa popular da comunidade:\nimport kotlinx.coroutines.flow.* import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertEquals class ProcessadorTest { private fun numerosFlow() = flowOf(1, 2, 3, 4, 5) @Test fun `deve filtrar e transformar corretamente`() = runTest { val resultado = numerosFlow() .filter { it % 2 != 0 } .map { it * 10 } .toList() assertEquals(listOf(10, 30, 50), resultado) } @Test fun `deve emitir valores do StateFlow`() = runTest { val stateFlow = MutableStateFlow(\u0026#34;inicial\u0026#34;) val valores = mutableListOf\u0026lt;String\u0026gt;() val job = launch { stateFlow.take(3).toList(valores) } stateFlow.value = \u0026#34;segundo\u0026#34; stateFlow.value = \u0026#34;terceiro\u0026#34; job.join() assertEquals(listOf(\u0026#34;inicial\u0026#34;, \u0026#34;segundo\u0026#34;, \u0026#34;terceiro\u0026#34;), valores) } } O toList() e o jeito mais simples de coletar todos os valores de um flow finito para verificação. Para flows infinitos ou que dependem de tempo, o Turbine oferece assercoesadicionais como awaitItem() e awaitComplete(). Para mais sobre testes, consulte o guia de testes em Kotlin.\nFlow no Android com Lifecycle No Android, coletar flows requer cuidado com o ciclo de vida para evitar vazamentos de memória e processamento desnecessário quando a tela não esta visivel:\nimport androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch class ListaViewModel( private val repositorio: ProdutoRepositorio ) : ViewModel() { private val _uiState = MutableStateFlow\u0026lt;UiState\u0026gt;(UiState.Carregando) val uiState: StateFlow\u0026lt;UiState\u0026gt; = _uiState.asStateFlow() init { viewModelScope.launch { repositorio.buscarProdutos() .catch { erro -\u0026gt; _uiState.value = UiState.Erro(erro.message ?: \u0026#34;Erro desconhecido\u0026#34;) } .collect { produtos -\u0026gt; _uiState.value = UiState.Sucesso(produtos) } } } } sealed class UiState { object Carregando : UiState() data class Sucesso(val produtos: List\u0026lt;String\u0026gt;) : UiState() data class Erro(val mensagem: String) : UiState() } // Na Activity ou Fragment, use repeatOnLifecycle // lifecycleScope.launch { // repeatOnLifecycle(Lifecycle.State.STARTED) { // viewModel.uiState.collect { state -\u0026gt; // when (state) { // is UiState.Carregando -\u0026gt; mostrarLoading() // is UiState.Sucesso -\u0026gt; mostrarProdutos(state.produtos) // is UiState.Erro -\u0026gt; mostrarErro(state.mensagem) // } // } // } // } O repeatOnLifecycle garante que a coleta só acontece quando o lifecycle esta no estado especificado (normalmente STARTED). Quando a Activity vai para background, a coleta e cancelada automaticamente e retomada ao voltar para foreground. Para entender melhor como coroutines se encaixam nesse cenário, confira o guia completo de coroutines.\nConclusão Kotlin Flow e a abordagem moderna para programação reativa no ecossistema Kotlin. Cold flows para operações sob demanda, StateFlow para estado da UI, SharedFlow para eventos, e um conjunto rico de operadores para transformar e combinar dados. A integração nativa com coroutines torna tudo mais simples e previsivel do que alternativas como RxJava. Se você esta construindo aplicações Android, o Flow combinado com o lifecycle-aware collection e praticamente a escolha padrão hoje. Para projetos backend, ele brilha em cenários de streaming de dados e processamento reativo com Ktor ou Spring WebFlux. Para comparação, Go usa goroutines e channels para concorrência, enquanto Rust oferece async/await com Tokio para streams reativos.\n","permalink":"https://kotlin.dev.br/guias/kotlin-flow-guia/","summary":"\u003cp\u003eKotlin Flow é a API de streams reativos da biblioteca de \u003ca href=\"/glossario/coroutine/\"\u003ecoroutines\u003c/a\u003e do Kotlin. Se você já trabalhou com RxJava, vai achar a API do Flow muito mais enxuta e natural, pois ela se integra diretamente com suspend functions e structured concurrency. Neste guia, vamos cobrir desde os fundamentos até padrões avançados de uso no Android e no backend, sempre com exemplos práticos que você pode adaptar aos seus projetos.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-um-flow\"\u003eO Que é um Flow\u003c/h2\u003e\n\u003cp\u003eUm \u003ca href=\"/glossario/flow/\"\u003eFlow\u003c/a\u003e é uma sequência de valores emitidos de forma assíncrona. Diferente de uma \u003ccode\u003eSequence\u003c/code\u003e, que e sincrona, o Flow permite que cada emissao envolva operações suspensas, como chamadas de rede ou consultas a banco de dados. A grande sacada e que o Flow e \u003cstrong\u003ecold\u003c/strong\u003e por padrão \u0026ndash; o código produtor só executa quando alguem começa a coletar.\u003c/p\u003e","title":"Kotlin Flow: Guia Completo em Português | Kotlin Brasil"},{"content":"Neste tutorial, você vai aprender a construir layouts com Jetpack Compose, a toolkit declarativa do Android para construcao de interfaces. Vamos explorar os composables fundamentais — Row, Column, Box — além de listas com LazyColumn, estruturas de tela com Scaffold é o poderoso sistema de Modifier. Se você já deu os primeiros passos com Compose no tutorial de Jetpack Compose básico, este guia vai expandir bastante o seu repertorio.\nA Filosofia de Layouts no Compose Diferente do sistema de Views clássico do Android, onde layouts são definidos em XML, no Compose tudo e feito em Kotlin. Cada elemento de interface é uma função Composable que descreve o que deve aparecer na tela. Nao existe mais LinearLayout, RelativeLayout ou ConstraintLayout em XML — agora você compoe a interface empilhando funções.\nEssa mudanca traz uma vantagem enorme: o layout é o comportamento vivem no mesmo lugar, facilitando a leitura é a manutenção do código.\nColumn: Organizando Elementos na Vertical O Column é o equivalente ao antigo LinearLayout com orientacao vertical. Ele empilha seus filhos de cima para baixo.\n@Composable fun CartaoUsuario() { Column( modifier = Modifier .fillMaxWidth() .padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { Text( text = \u0026#34;Maria Silva\u0026#34;, style = MaterialTheme.typography.headlineSmall ) Text( text = \u0026#34;Desenvolvedora Android\u0026#34;, style = MaterialTheme.typography.bodyMedium ) Text( text = \u0026#34;São Paulo, Brasil\u0026#34;, style = MaterialTheme.typography.bodySmall ) } } O parametro verticalArrangement controla como o espaco e distribuído entre os filhos. As opções mais comuns são Arrangement.Top, Arrangement.Center, Arrangement.SpaceBetween, Arrangement.SpaceEvenly e Arrangement.spacedBy().\nPara alinhar os filhos horizontalmente dentro de um Column, use o parametro horizontalAlignment:\nColumn( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { Text(\u0026#34;Texto centralizado\u0026#34;) Button(onClick = { }) { Text(\u0026#34;Botao centralizado\u0026#34;) } } Row: Organizando Elementos na Horizontal O Row funciona da mesma forma que o Column, mas na horizontal — os filhos são posicionados da esquerda para a direita.\n@Composable fun BarraDeAcoes() { Row( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { IconButton(onClick = { }) { Icon(Icons.Default.ArrowBack, contentDescription = \u0026#34;Voltar\u0026#34;) } Text( text = \u0026#34;Detalhes\u0026#34;, style = MaterialTheme.typography.titleMedium ) IconButton(onClick = { }) { Icon(Icons.Default.MoreVert, contentDescription = \u0026#34;Mais opções\u0026#34;) } } } Um recurso muito útil dentro de Row e o Modifier.weight(), que distribui o espaco disponivel proporcionalmente, semelhante ao layout_weight do antigo LinearLayout:\nRow(modifier = Modifier.fillMaxWidth()) { Text( text = \u0026#34;Nome do produto\u0026#34;, modifier = Modifier.weight(1f) ) Text( text = \u0026#34;R$ 49,90\u0026#34;, modifier = Modifier.width(100.dp), textAlign = TextAlign.End ) } Aqui, o nome do produto ocupa todo o espaco restante enquanto o preco mantém uma largura fixa.\nBox: Sobreposicao de Elementos O Box permite empilhar elementos um sobre o outro, como camadas. E o equivalente ao FrameLayout do sistema clássico.\n@Composable fun ImagemComBadge() { Box( modifier = Modifier.size(120.dp) ) { Image( painter = painterResource(id = R.drawable.foto_perfil), contentDescription = \u0026#34;Foto de perfil\u0026#34;, modifier = Modifier.fillMaxSize(), contentScale = ContentScale.Crop ) Badge( modifier = Modifier.align(Alignment.BottomEnd) ) { Text(\u0026#34;3\u0026#34;) } } } O parametro contentAlignment do Box define o alinhamento padrão dos filhos, enquanto Modifier.align() permite posicionar cada filho individualmente.\nO Sistema de Modifier O Modifier e provavelmente o conceito mais importante de todo o Jetpack Compose. Ele e uma cadeia de decoracoes que você aplica a qualquer composable para controlar tamanho, padding, alinhamento, cliques, cor de fundo e muito mais.\nText( text = \u0026#34;Elemento estilizado\u0026#34;, modifier = Modifier .fillMaxWidth() .padding(16.dp) .background( color = MaterialTheme.colorScheme.primaryContainer, shape = RoundedCornerShape(8.dp) ) .padding(12.dp) .clickable { /* acao ao clicar */ } ) A ordem dos modifiers importa. No exemplo acima, o primeiro padding cria espaco externo (como margin), o background aplica a cor, e o segundo padding cria espaco interno entre o fundo e o texto. Inverter a ordem muda completamente o resultado visual.\nAlguns dos modifiers mais usados no dia a dia:\nfillMaxWidth() / fillMaxHeight() / fillMaxSize() — preencher o espaco disponivel width() / height() / size() — dimensoes fixas padding() — espacamento interno ou externo (depende da ordem) background() — cor ou forma de fundo clip() — recortar o conteudo com uma forma border() — adicionar borda clickable {} — tornar o elemento clicavel weight() — distribuir espaco dentro de Row ou Column LazyColumn e LazyRow: Listas Eficientes Para listas longas, usar Column com muitos itens seria um desastre de performance, porque todos os itens seriam compostos de uma vez. E ai que entram LazyColumn e LazyRow, equivalentes ao RecyclerView do sistema clássico. Eles só compoem os itens que estao visiveis na tela.\n@Composable fun ListaDeProdutos(produtos: List\u0026lt;Produto\u0026gt;) { LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = PaddingValues(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { items( items = produtos, key = { it.id } ) { produto -\u0026gt; CartaoProduto(produto) } } } @Composable fun CartaoProduto(produto: Produto) { Card( modifier = Modifier.fillMaxWidth() ) { Column(modifier = Modifier.padding(16.dp)) { Text( text = produto.nome, style = MaterialTheme.typography.titleMedium ) Text( text = \u0026#34;R$ ${\u0026#34;%.2f\u0026#34;.format(produto.preco)}\u0026#34;, style = MaterialTheme.typography.bodyLarge ) } } } O parametro key e muito importante: ele permite que o Compose identifique cada item unicamente, otimizando recomposicoes quando a lista muda.\nPara listas horizontais, basta trocar para LazyRow:\nLazyRow( contentPadding = PaddingValues(horizontal = 16.dp), horizontalArrangement = Arrangement.spacedBy(12.dp) ) { items(categorias) { categoria -\u0026gt; ChipCategoria(categoria) } } Se você já usou RecyclerView, vai notar que o código com LazyColumn e significativamente mais simples — não há necessidade de Adapter, ViewHolder ou layout XML separado.\nScaffold: Estrutura de Tela Completa O Scaffold e um composable que fornece a estrutura básica de uma tela Material Design, incluindo slots para TopAppBar, BottomBar, FloatingActionButton e conteudo principal.\n@Composable fun TelaPrincipal() { Scaffold( topBar = { TopAppBar( title = { Text(\u0026#34;Meu Aplicativo\u0026#34;) }, colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.primary, titleContentColor = MaterialTheme.colorScheme.onPrimary ) ) }, floatingActionButton = { FloatingActionButton(onClick = { }) { Icon(Icons.Default.Add, contentDescription = \u0026#34;Adicionar\u0026#34;) } }, bottomBar = { NavigationBar { NavigationBarItem( selected = true, onClick = { }, icon = { Icon(Icons.Default.Home, contentDescription = \u0026#34;Inicio\u0026#34;) }, label = { Text(\u0026#34;Inicio\u0026#34;) } ) NavigationBarItem( selected = false, onClick = { }, icon = { Icon(Icons.Default.Settings, contentDescription = \u0026#34;Config\u0026#34;) }, label = { Text(\u0026#34;Config\u0026#34;) } ) } } ) { paddingValues -\u0026gt; LazyColumn( modifier = Modifier.padding(paddingValues) ) { items(50) { indice -\u0026gt; Text( text = \u0026#34;Item $indice\u0026#34;, modifier = Modifier .fillMaxWidth() .padding(16.dp) ) } } } } Repare no parametro paddingValues que o Scaffold passa para o conteudo. Ele inclui o espaco ocupado pela TopAppBar e pela BottomBar, garantindo que o conteudo não fique escondido atras deles. Sempre aplique esse padding ao conteudo principal.\nConstraintLayout no Compose Para layouts mais complexos onde os elementos precisam se posicionar em relação uns aos outros, o Compose oferece o ConstraintLayout. Ele exige uma dependência adicional:\n// build.gradle.kts implementation(\u0026#34;androidx.constraintlayout:constraintlayout-compose:1.1.0\u0026#34;) @Composable fun PerfilUsuario() { ConstraintLayout( modifier = Modifier .fillMaxWidth() .padding(16.dp) ) { val (foto, nome, cargo) = createRefs() Image( painter = painterResource(id = R.drawable.avatar), contentDescription = \u0026#34;Avatar\u0026#34;, modifier = Modifier .size(64.dp) .clip(CircleShape) .constrainAs(foto) { start.linkTo(parent.start) top.linkTo(parent.top) } ) Text( text = \u0026#34;Ana Costa\u0026#34;, style = MaterialTheme.typography.titleMedium, modifier = Modifier.constrainAs(nome) { start.linkTo(foto.end, margin = 12.dp) top.linkTo(foto.top) } ) Text( text = \u0026#34;Engenheira de Software\u0026#34;, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.constrainAs(cargo) { start.linkTo(nome.start) top.linkTo(nome.bottom, margin = 4.dp) } ) } } Embora o ConstraintLayout esteja disponivel, na prática a maioria dos layouts no Compose pode ser resolvida combinando Row, Column e Box. Reserve o ConstraintLayout para casos onde as relacoes entre elementos são realmente complexas.\nLayouts Responsivos Para criar layouts que se adaptam a diferentes tamanhos de tela — celulares, tablets, desktops — você pode usar BoxWithConstraints, que fornece as dimensoes disponiveis:\n@Composable fun LayoutAdaptavel() { BoxWithConstraints(modifier = Modifier.fillMaxSize()) { if (maxWidth \u0026gt; 600.dp) { // Layout para telas grandes: duas colunas Row(modifier = Modifier.fillMaxSize()) { ListaDeProdutos( produtos = produtos, modifier = Modifier.weight(1f) ) DetalhesProduto( produto = produtoSelecionado, modifier = Modifier.weight(1f) ) } } else { // Layout para telas pequenas: coluna unica ListaDeProdutos( produtos = produtos, modifier = Modifier.fillMaxSize() ) } } } Essa abordagem e fundamental para apps que rodam em dispositivos com tamanhos de tela variados, especialmente com o crescimento do Kotlin Multiplatform e do Compose Multiplatform.\nConclusão Dominar layouts no Jetpack Compose e questao de entender bem tres coisas: os composables de posicionamento (Column, Row, Box), o sistema de Modifier e os componentes de listas lazy. Com essas ferramentas, você consegue construir praticamente qualquer interface. O Scaffold organiza a estrutura geral da tela, e para casos excepcionais o ConstraintLayout esta a disposicao.\nA melhor forma de fixar esses conceitos e colocando a mao na massa. Pegue um design qualquer — pode ser uma tela do seu app favorito — e tente reproduzi-lo usando apenas Compose. Você vai perceber que a combinacao de funções, lambdas e composables torna o processo muito mais fluido do que o antigo sistema de Views em XML.\n","permalink":"https://kotlin.dev.br/tutoriais/jetpack-compose-layouts/","summary":"\u003cp\u003eNeste tutorial, você vai aprender a construir \u003cstrong\u003elayouts com Jetpack Compose\u003c/strong\u003e, a toolkit declarativa do Android para construcao de interfaces. Vamos explorar os composables fundamentais — Row, Column, Box — além de listas com LazyColumn, estruturas de tela com Scaffold é o poderoso sistema de \u003ca href=\"/glossario/modifier/\"\u003eModifier\u003c/a\u003e. Se você já deu os primeiros passos com Compose no tutorial de \u003ca href=\"/tutoriais/jetpack-compose-b%C3%A1sico/\"\u003eJetpack Compose básico\u003c/a\u003e, este guia vai expandir bastante o seu repertorio.\u003c/p\u003e\n\u003ch2 id=\"a-filosofia-de-layouts-no-compose\"\u003eA Filosofia de Layouts no Compose\u003c/h2\u003e\n\u003cp\u003eDiferente do sistema de Views clássico do Android, onde layouts são definidos em XML, no Compose tudo e feito em Kotlin. Cada elemento de interface é uma função \u003ca href=\"/glossario/composable/\"\u003eComposable\u003c/a\u003e que descreve o que deve aparecer na tela. Nao existe mais \u003ccode\u003eLinearLayout\u003c/code\u003e, \u003ccode\u003eRelativeLayout\u003c/code\u003e ou \u003ccode\u003eConstraintLayout\u003c/code\u003e em XML — agora você compoe a interface empilhando funções.\u003c/p\u003e","title":"Layouts com Jetpack Compose Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Se você pesquisou linguagem do Android e caiu aqui, já pode comemorar: este é o guia mais completo em português sobre Kotlin, a linguagem que o Google escolheu como oficial para desenvolvimento Android. Vamos cobrir tudo — o que é Kotlin, por que ela domina o ecossistema Android, como começar, é o que esperar do mercado brasileiro em 2026.\nEste é um guia de referência. Salve nos favoritos e volte sempre que precisar.\nO que É Kotlin? Kotlin é uma linguagem de programação moderna, concisa e segura, criada pela JetBrains — a mesma empresa por trás do IntelliJ IDEA. Foi lançada oficialmente em 2016 e, desde 2019, é a linguagem preferencial recomendada pelo Google para desenvolvimento Android.\nMas Kotlin não é só Android. Ela roda na JVM (Java Virtual Machine), compila para JavaScript e até para código nativo via Kotlin/Native. Isso significa que, ao aprender Kotlin, você abre portas para:\nDesenvolvimento Android (o uso mais popular) Backend com Spring Boot e Ktor Aplicações multiplataforma com Kotlin Multiplatform (KMP) Scripts e automações Kotlin foi pensada para resolver as dores do Java: código verboso, null pointer exceptions constantes e falta de recursos modernos. O resultado? Uma linguagem que é 100% interoperável com Java, mas infinitamente mais agradável de escrever.\nQuer um mergulho mais profundo no básico? Confira nosso guia O que É Kotlin: Guia Completo.\nKotlin: A Linguagem Oficial do Android Desde o Google I/O 2019, Kotlin é a linguagem número 1 para Android. Não é exagero — é fato oficial. O Google declarou que o desenvolvimento Android é \u0026ldquo;Kotlin-first\u0026rdquo;, e isso muda tudo:\nO que significa \u0026ldquo;Kotlin-first\u0026rdquo;? Toda nova API e biblioteca oficial do Android é projetada primeiro em Kotlin A documentação oficial do Android prioriza exemplos em Kotlin O Jetpack Compose — o framework moderno de UI — é escrito 100% em Kotlin Novos recursos do Android Studio são otimizados para Kotlin Números que impressionam (2026) Métrica Valor Apps no Google Play usando Kotlin 85%+ dos top 1000 Adoção entre devs Android ~95% Bibliotecas Jetpack com KTX 100% Vagas Android no Brasil pedindo Kotlin ~90% Jetpack Compose: o futuro da UI Android O Jetpack Compose é o toolkit declarativo de UI do Android, e ele só existe em Kotlin. Não tem como usar Compose com Java — ponto final. Se você quer fazer UI moderna no Android, precisa de Kotlin.\n@Composable fun Saudacao(nome: String) { Card( modifier = Modifier .fillMaxWidth() .padding(16.dp) ) { Text( text = \u0026#34;Olá, $nome! Bem-vindo ao app.\u0026#34;, style = MaterialTheme.typography.headlineMedium, modifier = Modifier.padding(16.dp) ) } } Esse exemplo cria um card com saudação em poucas linhas. Em XML + Java, o equivalente levaria 3x mais código.\nQuer montar seu primeiro app? Veja o guia prático Kotlin para Android.\nPor que Escolher Kotlin como Linguagem para Android? Se você está decidindo qual linguagem para Android aprender, aqui vai a resposta curta: Kotlin, sem dúvida. Mas vamos ao porquê.\n1. Null Safety (Segurança contra Nulos) O famigerado NullPointerException é o bug mais comum em Java. Em Kotlin, o sistema de tipos diferencia valores que podem ser nulos dos que não podem:\n// Não compila se \u0026#39;nome\u0026#39; for null val nome: String = \u0026#34;Diego\u0026#34; // Aceita null, mas exige tratamento explícito val apelido: String? = null println(apelido?.length ?: \u0026#34;Sem apelido\u0026#34;) Isso elimina uma classe inteira de bugs em tempo de compilação, antes do app chegar ao usuário.\nSaiba mais em Null Safety em Kotlin: Guia Completo.\n2. Código Conciso e Legível Kotlin elimina o boilerplate. Compare a criação de uma data class:\nJava (20+ linhas):\npublic class Usuario { private String nome; private int idade; // constructor, getters, setters, equals, hashCode, toString... } Kotlin (1 linha):\ndata class Usuario(val nome: String, val idade: Int) Menos código = menos bugs = mais produtividade.\n3. Coroutines para Async Programação assíncrona no Android é essencial (chamadas de rede, banco de dados, etc.). Com Coroutines, Kotlin torna isso simples e legível:\nviewModelScope.launch { val usuario = repository.buscarUsuario(id) // Suspende, nao bloqueia _uiState.value = UiState.Sucesso(usuario) } Nada de callbacks aninhados, AsyncTask ou RxJava complexo. Coroutines são nativas da linguagem.\nAprofunde-se em Coroutines em Kotlin: Guia Completo.\n4. Interoperabilidade Total com Java Tem um projeto legado em Java? Sem problema. Kotlin é 100% interoperável com Java. Você pode:\nChamar código Java a partir de Kotlin (e vice-versa) Migrar arquivos gradualmente, um por um Usar qualquer biblioteca Java existente Veja a comparação completa em Kotlin vs Java.\n5. Extension Functions Kotlin permite adicionar funcionalidades a classes existentes sem herança ou wrappers:\nfun String.primeiraMaiuscula(): String { return this.replaceFirstChar { it.uppercase() } } val nome = \u0026#34;kotlin\u0026#34;.primeiraMaiuscula() // \u0026#34;Kotlin\u0026#34; Isso é poderoso para criar APIs fluentes e código expressivo.\nVeja mais em Extension Functions em Kotlin.\nKotlin Linguagem: Recursos que Fazem a Diferença O que faz de Kotlin uma linguagem tão especial vai além do Android. Aqui estão os recursos que desenvolvedores mais amam:\nData Classes Modelos de dados em uma linha, com equals(), hashCode(), toString() e copy() gerados automaticamente:\ndata class Produto( val id: Long, val nome: String, val preco: Double ) val p1 = Produto(1, \u0026#34;Camiseta Kotlin\u0026#34;, 89.90) val p2 = p1.copy(preco = 79.90) // Copia com preço alterado Sealed Classes Perfeitas para representar estados finitos — essenciais no Jetpack Compose:\nsealed class ResultadoApi\u0026lt;out T\u0026gt; { data class Sucesso\u0026lt;T\u0026gt;(val dados: T) : ResultadoApi\u0026lt;T\u0026gt;() data class Erro(val mensagem: String) : ResultadoApi\u0026lt;Nothing\u0026gt;() object Carregando : ResultadoApi\u0026lt;Nothing\u0026gt;() } // Uso com when (exaustivo — o compilador garante que todos os casos são tratados) when (resultado) { is ResultadoApi.Sucesso -\u0026gt; mostrarDados(resultado.dados) is ResultadoApi.Erro -\u0026gt; mostrarErro(resultado.mensagem) ResultadoApi.Carregando -\u0026gt; mostrarLoading() } Guia completo: Sealed Classes em Kotlin.\nKotlin DSL Kotlin permite criar DSLs (Domain-Specific Languages) que leem como linguagem natural. O Gradle Kotlin DSL é o exemplo mais famoso:\ndependencies { implementation(\u0026#34;org.jetbrains.kotlin:kotlin-stdlib\u0026#34;) implementation(\u0026#34;androidx.compose.ui:ui:1.7.0\u0026#34;) testImplementation(\u0026#34;junit:junit:4.13.2\u0026#34;) } Saiba mais em Kotlin DSL: Guia Completo.\nKotlin Flow Para streams de dados reativos, Flow é a resposta moderna de Kotlin:\nfun buscarCotacoes(): Flow\u0026lt;Cotacao\u0026gt; = flow { while (true) { emit(api.getCotacaoAtual()) delay(5000) // Atualiza a cada 5 segundos } } Aprofunde-se em Kotlin Flow: Guia Completo.\nComo Começar com Kotlin para Android Quer colocar a mão na massa? Aqui vai o caminho mais rápido:\nPasso 1: Instale o Android Studio Baixe o Android Studio — ele já vem com suporte completo a Kotlin. Na versão atual (Ladybug+), Kotlin é a linguagem padrão para novos projetos.\nPasso 2: Crie seu Primeiro Projeto Abra o Android Studio → New Project Escolha Empty Activity (com Compose) Linguagem: Kotlin (já vem selecionada) Minimum SDK: API 24 (cobre 99%+ dos dispositivos) Passo 3: Entenda a Estrutura app/ ├── src/main/ │ ├── java/com/exemplo/meuapp/ │ │ └── MainActivity.kt # Activity principal │ ├── res/ # Recursos (imagens, strings) │ └── AndroidManifest.xml # Configuração do app ├── build.gradle.kts # Dependências (Kotlin DSL) └── gradle/libs.versions.toml # Catálogo de versoes Passo 4: Seu Primeiro Código class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MeuAppTheme { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { Saudacao(\u0026#34;Mundo\u0026#34;) } } } } } @Composable fun Saudacao(nome: String) { Text(text = \u0026#34;Olá, $nome!\u0026#34;) } Passo 5: Aprenda o Essencial A ordem recomendada para estudar:\nSintaxe básica: variáveis, funções, controle de fluxo Null safety: o diferencial de Kotlin Classes e objetos: data classes, sealed classes, companion objects Coroutines: programação assíncrona Jetpack Compose: UI declarativa Arquitetura: MVVM, Clean Architecture, Hilt Tutorial passo a passo: Kotlin para Android: Guia Completo.\nKotlin Além do Android Kotlin não é só Android. A linguagem está crescendo rapidamente em outras áreas:\nKotlin Multiplatform (KMP) Compartilhe lógica de negócios entre Android, iOS, Web e Desktop com um único código-base em Kotlin. Em 2026, o KMP já é estável e adotado por empresas como Netflix, Philips e Cash App.\n// Código compartilhado — roda em Android, iOS e Web expect fun plataformaAtual(): String class Repositorio { fun buscarDados(): List\u0026lt;Item\u0026gt; { // Lógica compartilhada entre plataformas } } Guia completo: Kotlin Multiplatform: Guia Completo.\nBackend com Spring Boot Kotlin é uma linguagem de primeira classe no Spring Boot. Combinando Kotlin com Spring, você tem um stack moderno para APIs e microsserviços:\n@RestController class ApiController(private val service: ProdutoService) { @GetMapping(\u0026#34;/produtos\u0026#34;) suspend fun listar(): List\u0026lt;Produto\u0026gt; = service.listarTodos() @PostMapping(\u0026#34;/produtos\u0026#34;) suspend fun criar(@RequestBody produto: Produto): Produto = service.salvar(produto) } Saiba mais em Kotlin com Spring Boot: Guia Completo.\nServer-side com Ktor Para quem quer algo mais leve que Spring, o Ktor é um framework feito pela JetBrains, 100% Kotlin e baseado em coroutines:\nfun main() { embeddedServer(Netty, port = 8080) { routing { get(\u0026#34;/\u0026#34;) { call.respondText(\u0026#34;Olá do Ktor!\u0026#34;) } } }.start(wait = true) } Kotlin em 2026: Mercado e Carreira no Brasil Se você está pensando em carreira, Kotlin é uma aposta segura:\nMercado de Trabalho Aspecto Dados (Brasil, 2026) Vagas abertas com Kotlin ~5.000+ no LinkedIn Salário médio (Pleno) R$ 10.000 - R$ 16.000 Salário médio (Sênior) R$ 16.000 - R$ 25.000+ Formato mais comum Remoto ou híbrido Requisitos frequentes Kotlin, Jetpack Compose, MVVM, CI/CD Tendências para 2026 Kotlin Multiplatform estável — empresas migrando de Flutter/React Native Compose Multiplatform — UI compartilhada entre Android, iOS e Desktop Kotlin para IA/ML — integração crescente com modelos de machine learning Server-side Kotlin — crescimento no backend com Ktor 3.0 e Spring Boot 4 Kotlin Notebook — análise de dados e prototipagem rápida Leia mais em Carreira Kotlin: Guia Completo.\nGlossário Rápido Precisa de uma referência rápida? Confira nosso Glossário Kotlin com 30+ termos explicados em português, incluindo:\nO que é JVM O que é Null Safety O que são Coroutines O que é Jetpack Compose O que é Data Class Perguntas Frequentes sobre Kotlin Kotlin é difícil de aprender? Não. Se você já conhece Java, a transição é natural — a maioria dos conceitos são os mesmos, com sintaxe mais limpa. Se está começando do zero, Kotlin é mais simples que Java como primeira linguagem. A comunidade brasileira está crescendo, e existem ótimos recursos em português.\nKotlin vai substituir Java? Não completamente. Java continua dominante em backend corporativo (bancos, fintechs legadas). Mas no Android, Kotlin já substituiu Java na prática — 95%+ dos novos projetos usam Kotlin. As duas linguagens coexistem na JVM.\nPreciso saber Java antes de aprender Kotlin? Não é obrigatório, mas ajuda. Kotlin roda na JVM e é interoperável com Java, então entender conceitos da JVM facilita. Porém, muitos desenvolvedores aprendem Kotlin diretamente sem problemas.\nKotlin serve só para Android? Não! Kotlin é multiplataforma: serve para backend (Spring Boot, Ktor), desenvolvimento web (Kotlin/JS), aplicações desktop, iOS (via KMP) e até scripts. O Android é o caso de uso mais popular, mas não o único.\nQual IDE usar para programar em Kotlin? Android Studio para desenvolvimento Android (baseado no IntelliJ IDEA). Para projetos não-Android, use o IntelliJ IDEA Community (gratuito) ou Ultimate. O VS Code também tem suporte via extensões, mas a experiência é inferior.\nKotlin é uma linguagem do Google? Não. Kotlin foi criada pela JetBrains, uma empresa tcheca. O Google adotou Kotlin como linguagem oficial para Android em 2017 e como preferencial em 2019, mas a linguagem é mantida pela JetBrains e pela Kotlin Foundation.\nQuanto tempo leva para aprender Kotlin? Com dedicação diária, a sintaxe básica leva 2-4 semanas. Para se sentir produtivo em projetos Android reais, 2-3 meses. Para nível pleno com arquitetura e boas práticas, 6-12 meses de experiência prática.\nPosso usar Kotlin em projetos Java existentes? Sim! Kotlin é 100% interoperável com Java. Você pode adicionar arquivos Kotlin a um projeto Java existente e migrar gradualmente, arquivo por arquivo. Essa é, na verdade, a estratégia recomendada pelo Google.\nConclusão Kotlin é, sem dúvida, a linguagem do Android em 2026 — e vai muito além disso. Com null safety, coroutines, Jetpack Compose e Kotlin Multiplatform, ela oferece tudo que um desenvolvedor moderno precisa.\nSe está começando, não existe momento melhor. O ecossistema está maduro, o mercado está aquecido e a comunidade brasileira está mais ativa do que nunca.\nPróximos passos recomendados: Leia O que É Kotlin: Guia Completo para entender os fundamentos Siga o tutorial Kotlin para Android e crie seu primeiro app Explore nosso Glossário Kotlin para referência rápida Confira as oportunidades de carreira com Kotlin Este guia é atualizado regularmente. Última atualização: março de 2026.\n","permalink":"https://kotlin.dev.br/linguagem-do-android/","summary":"\u003cp\u003eSe você pesquisou \u003cstrong\u003elinguagem do Android\u003c/strong\u003e e caiu aqui, já pode comemorar: este é o guia mais completo em português sobre \u003cstrong\u003eKotlin\u003c/strong\u003e, a linguagem que o Google escolheu como oficial para desenvolvimento Android. Vamos cobrir tudo — o que é Kotlin, por que ela domina o ecossistema Android, como começar, é o que esperar do mercado brasileiro em 2026.\u003c/p\u003e\n\u003cp\u003eEste é um guia de referência. Salve nos favoritos e volte sempre que precisar.\u003c/p\u003e","title":"Linguagem do Android: Tudo sobre Kotlin em 2026"},{"content":"Kotlin nasceu como uma linguagem multiparadigma, é um dos seus grandes trunfos é o suporte robusto a programação funcional sem abrir mao da orientacao a objetos. Se você vem do Java, vai perceber que Kotlin torna o estilo funcional muito mais acessivel e expressivo. Neste guia, vamos explorar cada conceito fundamental da programação funcional em Kotlin, com exemplos práticos que você pode aplicar no dia a dia dos seus projetos.\nFunções como Cidadas de Primeira Classe Em Kotlin, funções são cidadas de primeira classe. Isso significa que você pode armazenar funções em variaveis, passa-las como argumentos para outras funções e retorna-las como resultado. Esse conceito é a base de tudo que vamos ver ao longo deste guia.\nval saudacao: (String) -\u0026gt; String = { nome -\u0026gt; \u0026#34;Ola, $nome!\u0026#34; } fun main() { println(saudacao(\u0026#34;Kotlin Brasil\u0026#34;)) // Saida: Ola, Kotlin Brasil! val funcoes = listOf\u0026lt;(Int) -\u0026gt; Int\u0026gt;( { it * 2 }, { it + 10 }, { it * it } ) funcoes.forEach { f -\u0026gt; println(f(5)) } // Saida: 10, 15, 25 } Repare que a variavel saudacao armazena uma lambda diretamente. Nao existe nenhuma cerimonia extra \u0026ndash; basta declarar o tipo funcional e atribuir o bloco de código. Isso já e radicalmente diferente do que você encontra no Java, onde seria necessário usar interfaces funcionais ou classes anonimas.\nFunções de Alta Ordem Uma função de alta ordem (higher-order function) e aquela que recebe outras funções como parametro ou retorna uma função. A biblioteca padrão do Kotlin esta repleta delas: map, filter, fold, reduce, flatMap, entre muitas outras.\nfun \u0026lt;T\u0026gt; List\u0026lt;T\u0026gt;.filtrarE( predicado1: (T) -\u0026gt; Boolean, predicado2: (T) -\u0026gt; Boolean ): List\u0026lt;T\u0026gt; { return this.filter { predicado1(it) \u0026amp;\u0026amp; predicado2(it) } } fun main() { val numeros = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) val resultado = numeros.filtrarE( predicado1 = { it \u0026gt; 3 }, predicado2 = { it % 2 == 0 } ) println(resultado) // [4, 6, 8, 10] } A função filtrarE recebe dois predicados e aplica ambos ao mesmo tempo. Esse padrão e muito útil para construir pipelines de filtragem flexiveis, especialmente quando os criterios vem de fontes diferentes, como inputs do usuário ou configurações dinamicas.\nLambdas e Sintaxe Concisa Kotlin oferece uma sintaxe de lambda extremamente enxuta. Quando uma lambda tem apenas um parametro, você pode usar it como referência implicita. Alem disso, se a lambda for o ultimo argumento de uma função, ela pode ficar fora dos parenteses.\nval nomes = listOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;, \u0026#34;Carlos\u0026#34;, \u0026#34;Diana\u0026#34;) // Sintaxe completa val maiusculas1 = nomes.map({ nome: String -\u0026gt; nome.uppercase() }) // Tipo inferido val maiusculas2 = nomes.map({ nome -\u0026gt; nome.uppercase() }) // Lambda fora dos parenteses val maiusculas3 = nomes.map { nome -\u0026gt; nome.uppercase() } // Usando it val maiusculas4 = nomes.map { it.uppercase() } // Referência de funcao val maiusculas5 = nomes.map(String::uppercase) Todas as cinco formas produzem o mesmo resultado. No dia a dia, as formas mais concisas (com it ou referência de função) são as preferidas pela comunidade. Se você quer se aprofundar em como lambdas se conectam com coroutines, confira o guia completo de coroutines.\nFunções Puras e Imutabilidade Uma função pura e aquela que, dados os mesmos argumentos, sempre retorna o mesmo resultado e não causa efeitos colaterais. Esse conceito esta no coracao da programação funcional e Kotlin facilita muito a sua adoção por meio da palavra-chave val e das coleções imutáveis.\n// Função pura: sem efeitos colaterais, resultado previsivel fun calcularDesconto(preco: Double, percentual: Double): Double { return preco * (1.0 - percentual / 100.0) } // Uso de val para imutabilidade data class Produto(val nome: String, val preco: Double) fun aplicarDesconto(produtos: List\u0026lt;Produto\u0026gt;, percentual: Double): List\u0026lt;Produto\u0026gt; { return produtos.map { it.copy(preco = calcularDesconto(it.preco, percentual)) } } fun main() { val catálogo = listOf( Produto(\u0026#34;Teclado\u0026#34;, 250.0), Produto(\u0026#34;Mouse\u0026#34;, 120.0), Produto(\u0026#34;Monitor\u0026#34;, 1800.0) ) val comDesconto = aplicarDesconto(catálogo, 10.0) println(comDesconto) // O catálogo original permanece intacto println(catálogo) } Repare que usamos copy da data class para criar novas instancias em vez de modificar as existentes. A lista original catálogo nunca e alterada. Esse padrão de imutabilidade reduz drasticamente os bugs relacionados a estado compartilhado, especialmente em ambientes concorrentes.\nComposição de Funções Composição de funções e o ato de combinar funções simples para criar funções mais complexas. Em matematica, a composição de f e g e f(g(x)). Kotlin não tem um operador nativo de composição, mas e trivial criar um:\ninfix fun \u0026lt;A, B, C\u0026gt; ((B) -\u0026gt; C).comp(outra: (A) -\u0026gt; B): (A) -\u0026gt; C { return { a: A -\u0026gt; this(outra(a)) } } fun duplicar(x: Int): Int = x * 2 fun incrementar(x: Int): Int = x + 1 fun paraTexto(x: Int): String = \u0026#34;Resultado: $x\u0026#34; fun main() { val pipeline = ::paraTexto comp ::duplicar comp ::incrementar println(pipeline(5)) // Resultado: 12 // Execução: incrementar(5) = 6 -\u0026gt; duplicar(6) = 12 -\u0026gt; paraTexto(12) } A composição permite criar pipelines de transformacao reusaveis. Você define cada etapa isoladamente, testa cada uma separadamente e depois as compoe. Isso torna o código muito mais modular é fácil de manter.\nCurrying Currying e a técnica de transformar uma função que recebe múltiplos argumentos em uma sequência de funções que recebem um argumento de cada vez. Embora Kotlin não tenha currying nativo, implementa-lo e simples:\nfun \u0026lt;A, B, C\u0026gt; curry(f: (A, B) -\u0026gt; C): (A) -\u0026gt; (B) -\u0026gt; C { return { a: A -\u0026gt; { b: B -\u0026gt; f(a, b) } } } fun somar(a: Int, b: Int): Int = a + b fun main() { val somarCurried = curry(::somar) val somar5 = somarCurried(5) println(somar5(3)) // 8 println(somar5(10)) // 15 // Aplicação parcial diretamente val formatarMoeda = { simbolo: String -\u0026gt; { valor: Double -\u0026gt; \u0026#34;$simbolo %.2f\u0026#34;.format(valor) } } val formatarReais = formatarMoeda(\u0026#34;R$\u0026#34;) println(formatarReais(1499.90)) // R$ 1499.90 } Currying e particularmente útil quando você precisa de aplicação parcial \u0026ndash; fixar alguns parametros de uma função e gerar uma nova função mais específica. No exemplo acima, somar5 e uma versão especializada de somar que sempre soma 5.\nTail Recursion Recursão e um pilar da programação funcional, mas recursão clássica pode causar StackOverflowError para entradas grandes. Kotlin resolve isso com a palavra-chave tailrec, que otimiza funções recursivas de cauda convertendo-as em loops internamente:\ntailrec fun fatorial(n: Long, acumulador: Long = 1): Long { return if (n \u0026lt;= 1) acumulador else fatorial(n - 1, n * acumulador) } tailrec fun fibonacci(n: Int, a: Long = 0, b: Long = 1): Long { return if (n == 0) a else fibonacci(n - 1, b, a + b) } fun main() { println(fatorial(20)) // 2432902008176640000 println(fibonacci(50)) // 12586269025 } Para que tailrec funcione, a chamada recursiva precisa ser a ultima operação da função. O compilador verifica isso e emite um aviso se a anotacao for usada incorretamente. Essa otimização e a mesma que linguagens como Scala e Erlang fazem automaticamente.\nAvaliacao Lazy com Sequences Quando você trabalha com coleções grandes, as operações map, filter e similares criam coleções intermediarias a cada passo. Sequences resolvem esse problema com avaliacao lazy, processando os elementos um a um através de toda a cadeia de operações:\nfun main() { val resultado = (1..1_000_000) .asSequence() .filter { it % 3 == 0 } .map { it * it } .filter { it \u0026gt; 1000 } .take(10) .toList() println(resultado) // [1089, 1296, 1521, 1764, 2025, 2304, 2601, 2916, 3249, 3600] } Sem asSequence(), cada operação geraria uma lista intermediaria de até um milhao de elementos. Com Sequences, os elementos são processados sob demanda e a cadeia para assim que os 10 elementos necessários são encontrados. Se você trabalha com fluxos assíncronos, o conceito de laziness também aparece no Kotlin Flow, que e a contraparte assíncrona das Sequences.\nA Biblioteca Arrow Arrow e a biblioteca de programação funcional mais popular do ecossistema Kotlin. Ela traz estruturas de dados e padrões consagrados do mundo funcional, como Either, Option, Validated e suporte a efeitos computacionais.\nimport arrow.core.Either import arrow.core.left import arrow.core.right import arrow.core.raise.either sealed class AppErro { data class UsuarioNaoEncontrado(val id: Long) : AppErro() data class SemPermissao(val acao: String) : AppErro() } fun buscarUsuario(id: Long): Either\u0026lt;AppErro, String\u0026gt; { return if (id \u0026gt; 0) \u0026#34;Usuario #$id\u0026#34;.right() else AppErro.UsuarioNaoEncontrado(id).left() } fun verificarPermissao(usuario: String, acao: String): Either\u0026lt;AppErro, String\u0026gt; { return if (acao != \u0026#34;deletar\u0026#34;) \u0026#34;$usuario pode $acao\u0026#34;.right() else AppErro.SemPermissao(acao).left() } fun main() { val resultado = either { val usuario = buscarUsuario(42).bind() val permissao = verificarPermissao(usuario, \u0026#34;editar\u0026#34;).bind() permissao } when (resultado) { is Either.Right -\u0026gt; println(\u0026#34;Sucesso: ${resultado.value}\u0026#34;) is Either.Left -\u0026gt; println(\u0026#34;Erro: ${resultado.value}\u0026#34;) } // Saida: Sucesso: Usuario #42 pode editar } O Either substitui o uso de exceptions para controle de fluxo, que e uma prática considerada inadequada na programação funcional. Com Either.Left representando o erro e Either.Right representando o sucesso, o fluxo de erro se torna explicito e composicional. O bloco either com bind() permite encadear operações que podem falhar de forma sequencial e limpa.\nCombinando Tudo na Prática Vamos juntar vários conceitos em um exemplo mais proximo da realidade \u0026ndash; um pipeline de processamento de dados:\ndata class Pedido( val id: Long, val valor: Double, val status: String, val clienteId: Long ) fun main() { val pedidos = listOf( Pedido(1, 150.0, \u0026#34;APROVADO\u0026#34;, 100), Pedido(2, 85.0, \u0026#34;PENDENTE\u0026#34;, 101), Pedido(3, 320.0, \u0026#34;APROVADO\u0026#34;, 100), Pedido(4, 45.0, \u0026#34;CANCELADO\u0026#34;, 102), Pedido(5, 210.0, \u0026#34;APROVADO\u0026#34;, 101) ) // Pipeline funcional: filtra, transforma e agrega val faturamentoPorCliente = pedidos .asSequence() .filter { it.status == \u0026#34;APROVADO\u0026#34; } .groupBy { it.clienteId } .mapValues { (_, pedidosCliente) -\u0026gt; pedidosCliente.sumOf { it.valor } } println(faturamentoPorCliente) // {100=470.0, 101=210.0} // Funções puras compostas val ehAprovado: (Pedido) -\u0026gt; Boolean = { it.status == \u0026#34;APROVADO\u0026#34; } val ehValorAlto: (Pedido) -\u0026gt; Boolean = { it.valor \u0026gt; 100.0 } val pedidosPremium = pedidos .filter { ehAprovado(it) \u0026amp;\u0026amp; ehValorAlto(it) } .sortedByDescending { it.valor } println(pedidosPremium.map { it.id }) // [3, 5, 1] } Esse tipo de pipeline e extremamente comum em aplicações reais. Cada função faz uma coisa só, os dados fluem de uma transformacao para outra e o resultado final e previsivel e testavel. Para cenários mais complexos envolvendo processamento assíncrono, você pode migrar essas pipelines para Flow com poucas alteracoes.\nConclusão A programação funcional em Kotlin não e uma questao de tudo ou nada. O grande barato da linguagem e justamente permitir que você misture paradigmas conforme a necessidade. Use funções puras e imutabilidade como padrão, recorra a funções de alta ordem para abstrair comportamentos e lance mao de composição e currying quando a complexidade pedir. Com Arrow na jogada, você tem acesso a ferramentas sofisticadas sem precisar abandonar o ecossistema Kotlin que já conhece. Se você quer continuar se aprofundando, confira também o guia de testes em Kotlin para aprender a testar funções puras e pipelines funcionais de forma eficiente. Para quem se interessa por programação funcional em outras linguagens, Rust também oferece suporte robusto a iteradores, closures e imutabilidade por padrão, e Python possui ferramentas funcionais como map, filter e reduce integradas à linguagem.\n","permalink":"https://kotlin.dev.br/guias/kotlin-funcional/","summary":"\u003cp\u003eKotlin nasceu como uma linguagem multiparadigma, é um dos seus grandes trunfos é o suporte robusto a programação funcional sem abrir mao da orientacao a objetos. Se você vem do Java, vai perceber que Kotlin torna o estilo funcional muito mais acessivel e expressivo. Neste guia, vamos explorar cada conceito fundamental da programação funcional em Kotlin, com exemplos práticos que você pode aplicar no dia a dia dos seus projetos.\u003c/p\u003e","title":"Programação Funcional em Kotlin: Guia Completo em Português | Kotlin Brasil"},{"content":"Sobre a vagaA Amazon busca uma pessoa Desenvolvedora de Software pleno para atuação presencial em Belo Horizonte, Minas Gerais.\nStack e práticas citadasLinguagens: Kotlin, Java, Python, Go, JavaScript, C, C++, C#, Clojure.Ambiente: UNIX/Linux e serviços web.Metodologias e práticas: Agile/Lean, Kanban, Scrum, RUP e XP.FormatoSenioridade: pleno.Modelo de trabalho: presencial.Local: Belo Horizonte, Minas Gerais, Brasil. ","permalink":"https://kotlin.dev.br/vagas/eo6c2kcir6w1oouj-amazon-desenvolvedor-de-software/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Amazon busca uma pessoa Desenvolvedora de Software pleno para atuação presencial em Belo Horizonte, Minas Gerais.\u003c/p\u003e\u003ch3\u003eStack e práticas citadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eLinguagens: Kotlin, Java, Python, Go, JavaScript, C, C++, C#, Clojure.\u003c/li\u003e\u003cli\u003eAmbiente: UNIX/Linux e serviços web.\u003c/li\u003e\u003cli\u003eMetodologias e práticas: Agile/Lean, Kanban, Scrum, RUP e XP.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eFormato\u003c/h3\u003e\u003cul\u003e\u003cli\u003eSenioridade: pleno.\u003c/li\u003e\u003cli\u003eModelo de trabalho: presencial.\u003c/li\u003e\u003cli\u003eLocal: Belo Horizonte, Minas Gerais, Brasil.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor de Software"},{"content":"\u0026ldquo;Será que vale a pena investir em Kotlin?\u0026rdquo; — se essa dúvida passa pela sua cabeça, este post é pra você. Vamos analisar o mercado de trabalho, faixas salariais, habilidades mais demandadas e como se preparar para uma carreira sólida com Kotlin em 2026.\nO cenário atual do Kotlin no Brasil Kotlin vem crescendo consistentemente no Brasil nos últimos anos. O que antes era \u0026ldquo;aquela linguagem alternativa pra Android\u0026rdquo; virou uma das tecnologias mais requisitadas no mercado. Alguns fatores que impulsionam esse crescimento:\nGoogle recomenda Kotlin como linguagem principal para Android desde 2019 Spring Boot tem suporte oficial de primeira classe Kotlin Multiplatform amadureceu e empresas estão adotando Fintechs e startups brasileiras abraçaram Kotlin no backend Grandes empresas como Nubank, iFood, Mercado Livre e PicPay usam Kotlin em produção Faixas salariais em 2026 Os valores abaixo são estimativas baseadas em pesquisas de mercado e vagas publicadas em plataformas brasileiras. Os valores referem-se a regime CLT para trabalho remoto:\nPara uma leitura focada no primeiro emprego, veja o guia específico de salário de desenvolvedor Kotlin júnior, com diferenças entre CLT, PJ e vagas remotas no Brasil.\nDesenvolvedor Android (Kotlin) Nível Faixa Salarial (CLT) Júnior R$ 3.500 - R$ 6.000 Pleno R$ 7.000 - R$ 12.000 Sênior R$ 13.000 - R$ 20.000 Especialista/Staff R$ 18.000 - R$ 28.000 Desenvolvedor Backend (Kotlin + Spring Boot) Nível Faixa Salarial (CLT) Júnior R$ 4.000 - R$ 7.000 Pleno R$ 8.000 - R$ 14.000 Sênior R$ 14.000 - R$ 22.000 Especialista/Staff R$ 20.000 - R$ 30.000 Trabalho remoto para empresas internacionais Para quem trabalha remoto para empresas de fora, os valores sobem consideravelmente. Desenvolvedores Kotlin sênior trabalhando para empresas americanas ou europeias podem ganhar entre US$ 5.000 e US$ 12.000/mês como PJ.\nHabilidades mais demandadas Analisando centenas de vagas publicadas no Brasil, as habilidades mais pedidas para desenvolvedores Kotlin são:\nPara Android Kotlin (óbvio, mas fluência mesmo) Jetpack Compose Arquitetura MVVM / MVI Coroutines e Flow Hilt / Koin para injeção de dependência Testes unitários e de UI CI/CD (GitHub Actions, Bitrise) Kotlin Multiplatform (diferencial crescente) Para Backend Kotlin com Spring Boot APIs REST e gRPC Bancos relacionais (PostgreSQL) e NoSQL (MongoDB, Redis) Docker e Kubernetes Mensageria (Kafka, RabbitMQ) Testes com JUnit 5 e Mockk Observabilidade (métricas, logs, traces) Arquitetura de microsserviços Habilidades transversais Não subestime as soft skills — elas pesam bastante nas entrevistas:\nComunicação clara (especialmente para trabalho remoto) Capacidade de resolver problemas de forma autônoma Inglês técnico (leitura obrigatória; conversação é diferencial) Code review construtivo Documentação e escrita técnica Como construir sua carreira com Kotlin Se você está começando (0-2 anos) Domine os fundamentos de Kotlin: tipos, null safety, coleções, lambdas Escolha uma trilha: Android ou Backend Faça projetos pessoais: publique no GitHub, mesmo que simples Contribua com open source: mesmo pequenas contribuições contam Participe da comunidade: eventos, meetups, grupos no Discord/Telegram // Exemplo: um projetinho simples pra portfólio // App de lista de tarefas com: // - Jetpack Compose (UI) // - Room (banco local) // - Coroutines + Flow (dados reativos) // - Hilt (injeção de dependência) // - Testes unitários com MockK data class Tarefa( val id: Long = 0, val titulo: String, val concluida: Boolean = false, val criadaEm: LocalDateTime = LocalDateTime.now() ) Se você é pleno (2-5 anos) Aprofunde em arquitetura: Clean Architecture, DDD, SOLID Domine coroutines e Flow: entenda internals, não só a API Aprenda a segunda trilha: se faz Android, aprenda backend (e vice-versa) Explore Kotlin Multiplatform: é o futuro e poucas pessoas dominam Seja mentor: ensinar solidifica seu conhecimento Se você é sênior (5+ anos) Torne-se referência: palestras, blog posts, open source Arquitetura de sistemas: design de sistemas escaláveis Liderança técnica: guiar times, fazer tech decisions Explore nichos: Kotlin para data engineering, ML, ou compiladores Considere trabalho remoto internacional: o salto salarial é significativo Onde encontrar vagas Kotlin As melhores plataformas para encontrar vagas Kotlin no Brasil:\nLinkedIn: filtrar por \u0026ldquo;Kotlin\u0026rdquo; + remoto GeekHunter: plataforma brasileira focada em devs Programathor: vagas de tecnologia no Brasil GitHub Jobs e StackOverflow Jobs: vagas internacionais Kotlinlang Slack: canal #jobs com vagas globais Comunidades brasileiras: grupos no Telegram e Discord Preparação para entrevistas Perguntas técnicas comuns As entrevistas para vagas Kotlin geralmente cobrem:\n// 1. Diferença entre val e var, const e companion object const val MAX_TENTATIVAS = 3 // compile-time constant class Config { companion object { val TIMEOUT = Duration.ofSeconds(30) // runtime constant } } // 2. Scope functions: let, run, with, apply, also val usuario = Usuario(\u0026#34;Karina\u0026#34;).apply { email = \u0026#34;karina@kotlin.dev.br\u0026#34; ativo = true } // 3. Sealed classes e when exaustivo sealed class Resultado\u0026lt;out T\u0026gt; { data class Sucesso\u0026lt;T\u0026gt;(val dados: T) : Resultado\u0026lt;T\u0026gt;() data class Erro(val mensagem: String) : Resultado\u0026lt;Nothing\u0026gt;() } // 4. Coroutines: diferença entre launch e async // launch: fire-and-forget, retorna Job // async: retorna Deferred\u0026lt;T\u0026gt;, precisa de await() para obter o resultado // 5. Collection operations val devsSenior = desenvolvedores .filter { it.experiência \u0026gt;= 5 } .sortedByDescending { it.salário } .take(10) .map { it.nome } Coding challenges Pratique em plataformas como LeetCode e HackerRank usando Kotlin. Aqui um exemplo típico:\n// Encontrar o par de numeros que soma ao target fun twoSum(nums: IntArray, target: Int): IntArray { val mapa = mutableMapOf\u0026lt;Int, Int\u0026gt;() nums.forEachIndexed { indice, numero -\u0026gt; val complemento = target - numero mapa[complemento]?.let { return intArrayOf(it, indice) } mapa[numero] = indice } throw IllegalArgumentException(\u0026#34;Nenhum par encontrado\u0026#34;) } O futuro de Kotlin Olhando pra frente, o ecossistema Kotlin só tende a crescer:\nKotlin Multiplatform se consolidando como solução mainstream Compose Multiplatform expandindo para iOS, web e desktop Kotlin para servidor ganhando cada vez mais espaço com Ktor 3.x Kotlin/Wasm abrindo portas para WebAssembly Inteligência artificial: Kotlin começando a aparecer em tooling para ML/AI Comunidade Kotlin no Brasil O Brasil tem uma comunidade Kotlin ativa e acolhedora. Participe:\nKotlin Brasil (kotlin.dev.br): conteúdo em português KotlinConf: conferência oficial da JetBrains GDG (Google Developer Groups): meetups locais com conteúdo Kotlin/Android DevFest: eventos anuais dos GDGs com trilhas de Kotlin Conclusão A carreira em Kotlin é promissora, bem remunerada e cheia de oportunidades. Seja para Android, backend ou multiplataforma, a demanda por profissionais qualificados em Kotlin só cresce. O melhor momento pra começar foi ontem — o segundo melhor é agora.\nInvista no seu aprendizado, construa seu portfólio, participe da comunidade e as oportunidades vão aparecer. Para ampliar suas oportunidades, considere aprender também Go para microsserviços ou Python para data science e IA — linguagens complementares que valorizam ainda mais seu perfil. Bora construir essa carreira juntos!\n","permalink":"https://kotlin.dev.br/blog/carreira-kotlin/","summary":"\u003cp\u003e\u0026ldquo;Será que vale a pena investir em Kotlin?\u0026rdquo; — se essa dúvida passa pela sua cabeça, este post é pra você. Vamos analisar o mercado de trabalho, faixas salariais, habilidades mais demandadas e como se preparar para uma carreira sólida com Kotlin em 2026.\u003c/p\u003e\n\u003ch2 id=\"o-cenário-atual-do-kotlin-no-brasil\"\u003eO cenário atual do Kotlin no Brasil\u003c/h2\u003e\n\u003cp\u003eKotlin vem crescendo consistentemente no Brasil nos últimos anos. O que antes era \u0026ldquo;aquela linguagem alternativa pra Android\u0026rdquo; virou uma das tecnologias mais requisitadas no mercado. Alguns fatores que impulsionam esse crescimento:\u003c/p\u003e","title":"Carreira Kotlin: Salário e Oportunidades em 2026 | Kotlin Brasil"},{"content":"Sobre a vagaA Wellhub busca uma pessoa Gerente de Engenharia de Software Fullstack para atuação remota no Brasil.\nStack técnicaReact e TypeScript no frontend.Go, Kotlin e Java no backend.Bancos de dados PostgreSQL e MySQL.APIs REST, AWS e práticas de CI/CD.Informações da vagaEmpresa: Wellhub.Modelo de trabalho: remoto.Localização: Brasil.Senioridade informada: nível pleno. ","permalink":"https://kotlin.dev.br/vagas/xs1dwwp6fb7h71qh-wellhub-gerente-de-engenharia-de-software-fullstack/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Wellhub busca uma pessoa Gerente de Engenharia de Software Fullstack para atuação remota no Brasil.\u003c/p\u003e\u003ch3\u003eStack técnica\u003c/h3\u003e\u003cul\u003e\u003cli\u003eReact e TypeScript no frontend.\u003c/li\u003e\u003cli\u003eGo, Kotlin e Java no backend.\u003c/li\u003e\u003cli\u003eBancos de dados PostgreSQL e MySQL.\u003c/li\u003e\u003cli\u003eAPIs REST, AWS e práticas de CI/CD.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eInformações da vaga\u003c/h3\u003e\u003cul\u003e\u003cli\u003eEmpresa: Wellhub.\u003c/li\u003e\u003cli\u003eModelo de trabalho: remoto.\u003c/li\u003e\u003cli\u003eLocalização: Brasil.\u003c/li\u003e\u003cli\u003eSenioridade informada: nível pleno.\u003c/li\u003e\u003c/ul\u003e","title":"Gerente de Engenharia de Software Fullstack"},{"content":"Se coroutines são o coração da programação assíncrona em Kotlin, Flow é o sistema circulatório. Enquanto uma suspend function retorna um único valor, um Flow emite múltiplos valores ao longo do tempo. É a resposta do Kotlin para programação reativa — e é muito mais simples do que RxJava.\nO que é Kotlin Flow? Flow é uma API de streams assíncronos construída sobre coroutines. Pense nele como uma sequência de valores que são computados de forma assíncrona. Diferente de Sequence (que é síncrono), Flow opera de forma não bloqueante e respeita cancelamento.\nimport kotlinx.coroutines.flow.* import kotlinx.coroutines.delay fun contagem(): Flow\u0026lt;Int\u0026gt; = flow { for (i in 1..5) { delay(500) // simula trabalho assíncrono emit(i) // emite o próximo valor } } suspend fun main() { contagem().collect { valor -\u0026gt; println(\u0026#34;Recebido: $valor\u0026#34;) } } Saída (uma a cada 500ms):\nRecebido: 1 Recebido: 2 Recebido: 3 Recebido: 4 Recebido: 5 Flow é frio (cold) Um conceito fundamental: Flow é cold — ou seja, o código dentro do builder flow { } só executa quando alguém chama collect. Se ninguém coleta, nada acontece:\nval meuFlow = flow { println(\u0026#34;Flow iniciou!\u0026#34;) // só executa quando collect() e chamado emit(1) emit(2) emit(3) } // Nada aconteceu ainda... println(\u0026#34;Antes do collect\u0026#34;) meuFlow.collect { println(it) } // Agora sim: \u0026#34;Flow iniciou!\u0026#34;, 1, 2, 3 Operadores essenciais Flow vem com uma coleção rica de operadores para transformar, filtrar e combinar streams:\nmap e filter suspend fun main() { (1..10).asFlow() .filter { it % 2 == 0 } // só pares .map { it * it } // eleva ao quadrado .collect { println(it) } // 4, 16, 36, 64, 100 } transform Para transformações mais complexas:\nfun buscarUsuarios(): Flow\u0026lt;Int\u0026gt; = (1..5).asFlow() suspend fun main() { buscarUsuarios() .transform { id -\u0026gt; emit(\u0026#34;Buscando usuário #$id...\u0026#34;) val usuario = buscarNoBanco(id) // suspend function emit(\u0026#34;Encontrado: ${usuario.nome}\u0026#34;) } .collect { println(it) } } take, drop e distinctUntilChanged suspend fun main() { val numeros = flowOf(1, 1, 2, 2, 3, 3, 4, 5, 5) numeros .distinctUntilChanged() // remove duplicatas consecutivas .drop(1) // pula o primeiro .take(3) // pega apenas 3 .collect { println(it) } // 2, 3, 4 } Combinando Flows zip: combinar par a par suspend fun main() { val nomes = flowOf(\u0026#34;Karina\u0026#34;, \u0026#34;João\u0026#34;, \u0026#34;Ana\u0026#34;) val linguagens = flowOf(\u0026#34;Kotlin\u0026#34;, \u0026#34;Java\u0026#34;, \u0026#34;Python\u0026#34;) nomes.zip(linguagens) { nome, linguagem -\u0026gt; \u0026#34;$nome programa em $linguagem\u0026#34; }.collect { println(it) } // Karina programa em Kotlin // João programa em Java // Ana programa em Python } combine: combinar com o valor mais recente val pesquisa = MutableStateFlow(\u0026#34;\u0026#34;) val filtro = MutableStateFlow(\u0026#34;todos\u0026#34;) val resultados: Flow\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt; = combine(pesquisa, filtro) { termo, tipo -\u0026gt; repository.buscar(termo, tipo) } O combine re-emite sempre que qualquer um dos flows muda — perfeito para buscas com filtros na UI.\nflatMapLatest: cancelar o anterior val termoDeBusca = MutableStateFlow(\u0026#34;\u0026#34;) val resultados = termoDeBusca .debounce(300) // espera 300ms sem digitação .distinctUntilChanged() .flatMapLatest { termo -\u0026gt; if (termo.isBlank()) flowOf(emptyList()) else buscarProdutos(termo) // cancela a busca anterior automaticamente } StateFlow e SharedFlow Enquanto Flow é cold, StateFlow e SharedFlow são hot — emitem valores independente de ter collectors.\nStateFlow: estado observável class CarrinhoViewModel : ViewModel() { private val _itens = MutableStateFlow\u0026lt;List\u0026lt;ItemCarrinho\u0026gt;\u0026gt;(emptyList()) val itens: StateFlow\u0026lt;List\u0026lt;ItemCarrinho\u0026gt;\u0026gt; = _itens.asStateFlow() val total: StateFlow\u0026lt;Double\u0026gt; = _itens .map { lista -\u0026gt; lista.sumOf { it.preco * it.quantidade } } .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = 0.0 ) fun adicionar(produto: Produto) { _itens.update { listaAtual -\u0026gt; listaAtual + ItemCarrinho(produto.nome, produto.preco, 1) } } } StateFlow sempre tem um valor (nunca é vazio) e só emite quando o valor muda. É a substituição moderna do LiveData no Android.\nSharedFlow: eventos class NotificacaoViewModel : ViewModel() { private val _eventos = MutableSharedFlow\u0026lt;Evento\u0026gt;() val eventos: SharedFlow\u0026lt;Evento\u0026gt; = _eventos.asSharedFlow() fun mostrarMensagem(texto: String) { viewModelScope.launch { _eventos.emit(Evento.Snackbar(texto)) } } fun navegar(rota: String) { viewModelScope.launch { _eventos.emit(Evento.Navegação(rota)) } } } sealed class Evento { data class Snackbar(val mensagem: String) : Evento() data class Navegação(val rota: String) : Evento() } SharedFlow é ideal para eventos que não devem ser \u0026ldquo;consumidos de novo\u0026rdquo; ao recompor a UI.\nFlow no Android com Compose A integração entre Flow e Jetpack Compose é perfeita:\n@Composable fun TelaCarrinho(viewModel: CarrinhoViewModel = viewModel()) { val itens by viewModel.itens.collectAsStateWithLifecycle() val total by viewModel.total.collectAsStateWithLifecycle() Column(modifier = Modifier.padding(16.dp)) { Text(\u0026#34;Carrinho de Compras\u0026#34;, style = MaterialTheme.typography.headlineMedium) LazyColumn(modifier = Modifier.weight(1f)) { items(itens) { item -\u0026gt; ListItem( headlineContent = { Text(item.nome) }, trailingContent = { Text(\u0026#34;R$ ${\u0026#34;%.2f\u0026#34;.format(item.preco)}\u0026#34;) } ) } } HorizontalDivider() Text( text = \u0026#34;Total: R$ ${\u0026#34;%.2f\u0026#34;.format(total)}\u0026#34;, style = MaterialTheme.typography.titleLarge, modifier = Modifier.padding(top = 8.dp) ) } } O collectAsStateWithLifecycle() é lifecycle-aware: para de coletar quando o app vai pra background e retoma quando volta. Essencial para economizar bateria.\nTratamento de erros fun dadosDoServidor(): Flow\u0026lt;Dados\u0026gt; = flow { val resultado = api.buscar() emit(resultado) }.catch { exception -\u0026gt; // Trata o erro e pode emitir um valor de fallback println(\u0026#34;Erro: ${exception.message}\u0026#34;) emit(Dados.vazio()) }.onStart { println(\u0026#34;Iniciando busca...\u0026#34;) }.onCompletion { causa -\u0026gt; if (causa == null) println(\u0026#34;Completou com sucesso\u0026#34;) else println(\u0026#34;Completou com erro: ${causa.message}\u0026#34;) } Boas práticas Use StateFlow para estado de UI, SharedFlow para eventos stateIn com WhileSubscribed: economiza recursos quando não há observers collectAsStateWithLifecycle: sempre no Android para lifecycle awareness flowOn para mudar dispatcher: flow.flowOn(Dispatchers.IO) em vez de mudar no collect Evite collect dentro de collect: use operadores como flatMapLatest ou combine Conclusão Kotlin Flow é programação reativa do jeito certo: simples, integrada com coroutines e sem a complexidade do RxJava. Se você trabalha com Android, dominar Flow é essencial em 2026. Para backend, Flow brilha em cenários de streaming e processamento de dados em tempo real. Conceitos similares existem em outras linguagens: Go usa channels para comunicação entre goroutines, enquanto Rust tem async streams com tokio.\nHora de deixar seus dados fluírem!\n","permalink":"https://kotlin.dev.br/blog/kotlin-flow/","summary":"\u003cp\u003eSe coroutines são o coração da programação assíncrona em Kotlin, Flow é o sistema circulatório. Enquanto uma suspend function retorna um único valor, um Flow emite \u003cstrong\u003emúltiplos valores ao longo do tempo\u003c/strong\u003e. É a resposta do Kotlin para programação reativa — e é muito mais simples do que RxJava.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-kotlin-flow\"\u003eO que é Kotlin Flow?\u003c/h2\u003e\n\u003cp\u003eFlow é uma API de streams assíncronos construída sobre coroutines. Pense nele como uma sequência de valores que são computados de forma assíncrona. Diferente de \u003ccode\u003eSequence\u003c/code\u003e (que é síncrono), Flow opera de forma não bloqueante e respeita cancelamento.\u003c/p\u003e","title":"Kotlin Flow: Programação Reativa em Português | Kotlin Brasil"},{"content":"Se você já usou Gradle com Kotlin, configurou rotas no Ktor ou montou layouts no Jetpack Compose, você já usou uma DSL sem perceber. DSL (Domain Specific Language) é um dos recursos mais elegantes de Kotlin, e neste post vamos entender como criar as nossas próprias.\nO que é uma DSL? Uma DSL é uma mini-linguagem projetada para um domínio específico. Diferente de uma linguagem de propósito geral (como Kotlin ou Java), uma DSL foca em resolver problemas de uma área particular de forma expressiva.\nExemplos de DSLs que você já conhece:\nSQL: linguagem para bancos de dados HTML: linguagem para páginas web Regex: linguagem para padrões de texto Em Kotlin, podemos criar DSLs internas — ou seja, DSLs que são Kotlin válido, mas parecem uma linguagem própria.\nA mágica por trás: lambdas com receiver O ingrediente secreto das DSLs em Kotlin é a lambda com receiver. Vamos entender passo a passo:\n// Função normal com lambda fun executar(bloco: () -\u0026gt; Unit) { bloco() } // Lambda COM receiver — dentro do bloco, `this` é do tipo StringBuilder fun construirString(bloco: StringBuilder.() -\u0026gt; Unit): String { val sb = StringBuilder() sb.bloco() // o StringBuilder e o receiver return sb.toString() } fun main() { val resultado = construirString { append(\u0026#34;Olá, \u0026#34;) // `this` é StringBuilder, então append() está disponível append(\u0026#34;mundo!\u0026#34;) appendLine() append(\u0026#34;Kotlin DSL é demais!\u0026#34;) } println(resultado) } O tipo StringBuilder.() -\u0026gt; Unit significa: \u0026ldquo;uma lambda onde o this é um StringBuilder\u0026rdquo;. Dentro dessa lambda, você pode chamar qualquer método de StringBuilder diretamente.\nCriando uma DSL para HTML Vamos construir uma DSL para gerar HTML — esse é o exemplo clássico:\nclass Tag(val nome: String) { val filhos = mutableListOf\u0026lt;Any\u0026gt;() val atributos = mutableMapOf\u0026lt;String, String\u0026gt;() fun atributo(chave: String, valor: String) { atributos[chave] = valor } operator fun String.unaryPlus() { filhos.add(this) } fun tag(nome: String, bloco: Tag.() -\u0026gt; Unit = {}): Tag { val novaTag = Tag(nome) novaTag.bloco() filhos.add(novaTag) return novaTag } fun div(bloco: Tag.() -\u0026gt; Unit = {}) = tag(\u0026#34;div\u0026#34;, bloco) fun h1(bloco: Tag.() -\u0026gt; Unit = {}) = tag(\u0026#34;h1\u0026#34;, bloco) fun p(bloco: Tag.() -\u0026gt; Unit = {}) = tag(\u0026#34;p\u0026#34;, bloco) fun a(href: String, bloco: Tag.() -\u0026gt; Unit = {}) = tag(\u0026#34;a\u0026#34;) { atributo(\u0026#34;href\u0026#34;, href) bloco() } override fun toString(): String { val attrs = if (atributos.isEmpty()) \u0026#34;\u0026#34; else atributos.entries.joinToString(\u0026#34; \u0026#34;, prefix = \u0026#34; \u0026#34;) { \u0026#34;${it.key}=\\\u0026#34;${it.value}\\\u0026#34;\u0026#34; } val conteudo = filhos.joinToString(\u0026#34;\u0026#34;) return \u0026#34;\u0026lt;$nome$attrs\u0026gt;$conteudo\u0026lt;/$nome\u0026gt;\u0026#34; } } fun html(bloco: Tag.() -\u0026gt; Unit): Tag { val root = Tag(\u0026#34;html\u0026#34;) root.bloco() return root } fun main() { val pagina = html { tag(\u0026#34;head\u0026#34;) { tag(\u0026#34;title\u0026#34;) { +\u0026#34;Kotlin Brasil\u0026#34; } } tag(\u0026#34;body\u0026#34;) { h1 { +\u0026#34;Bem-vindo ao Kotlin Brasil!\u0026#34; } p { +\u0026#34;Aprenda Kotlin em português.\u0026#34; } a(\u0026#34;https://kotlin.dev.br\u0026#34;) { +\u0026#34;Visite nosso site\u0026#34; } } } println(pagina) } Repare no +\u0026quot;texto\u0026quot; — usamos operator overloading (unaryPlus) para adicionar texto como filho. O resultado é código que parece HTML, mas é Kotlin puro.\nDSL para configuração DSLs são perfeitas para configuração tipada e validada em compile time:\ndata class ServidorConfig( var host: String = \u0026#34;localhost\u0026#34;, var porta: Int = 8080, var ssl: SslConfig? = null, var banco: BancoConfig? = null ) data class SslConfig( var certificado: String = \u0026#34;\u0026#34;, var chave: String = \u0026#34;\u0026#34; ) data class BancoConfig( var url: String = \u0026#34;\u0026#34;, var usuario: String = \u0026#34;\u0026#34;, var senha: String = \u0026#34;\u0026#34;, var poolSize: Int = 10 ) fun servidor(bloco: ServidorConfig.() -\u0026gt; Unit): ServidorConfig { return ServidorConfig().apply(bloco) } fun ServidorConfig.ssl(bloco: SslConfig.() -\u0026gt; Unit) { ssl = SslConfig().apply(bloco) } fun ServidorConfig.banco(bloco: BancoConfig.() -\u0026gt; Unit) { banco = BancoConfig().apply(bloco) } fun main() { val config = servidor { host = \u0026#34;api.kotlin.dev.br\u0026#34; porta = 443 ssl { certificado = \u0026#34;/certs/server.crt\u0026#34; chave = \u0026#34;/certs/server.key\u0026#34; } banco { url = \u0026#34;jdbc:postgresql://localhost:5432/kotlinbrasil\u0026#34; usuario = \u0026#34;admin\u0026#34; senha = \u0026#34;s3nh4-s3gur4\u0026#34; poolSize = 20 } } println(\u0026#34;Servidor: ${config.host}:${config.porta}\u0026#34;) println(\u0026#34;SSL: ${config.ssl != null}\u0026#34;) println(\u0026#34;Banco pool: ${config.banco?.poolSize}\u0026#34;) } Compare isso com um arquivo YAML ou properties — a DSL tem autocompletar, verificação de tipos e válidação em tempo de compilação.\nDSL para testes Criar DSLs para testes deixa o código muito mais legível:\nclass PedidoTestBuilder { var cliente: String = \u0026#34;Cliente Teste\u0026#34; var itens: MutableList\u0026lt;ItemPedido\u0026gt; = mutableListOf() var desconto: Double = 0.0 fun item(nome: String, preco: Double, quantidade: Int = 1) { itens.add(ItemPedido(nome, preco, quantidade)) } fun build() = Pedido(cliente, itens.toList(), desconto) } fun pedido(bloco: PedidoTestBuilder.() -\u0026gt; Unit): Pedido { return PedidoTestBuilder().apply(bloco).build() } // Uso nos testes — lê como uma história fun main() { val meuPedido = pedido { cliente = \u0026#34;Maria Silva\u0026#34; desconto = 10.0 item(\u0026#34;Camiseta Kotlin\u0026#34;, preco = 79.90, quantidade = 2) item(\u0026#34;Caneca JVM\u0026#34;, preco = 39.90) item(\u0026#34;Adesivo Coroutines\u0026#34;, preco = 9.90, quantidade = 5) } println(\u0026#34;Pedido de ${meuPedido.cliente}\u0026#34;) println(\u0026#34;Total de itens: ${meuPedido.itens.size}\u0026#34;) } @DslMarker: controlando o escopo Em DSLs aninhadas, pode acontecer de acessar receivers de escopos externos acidentalmente. O @DslMarker previne isso:\n@DslMarker annotation class HtmlDsl @HtmlDsl class Body { fun p(texto: String) { /* ... */ } fun div(bloco: Div.() -\u0026gt; Unit) { /* ... */ } } @HtmlDsl class Div { fun span(texto: String) { /* ... */ } // Não pode chamar p() do Body aqui — @DslMarker impede! } Isso torna a DSL mais segura e evita erros sutis de escopo.\nDSLs famosas do ecossistema Kotlin Você já usa DSLs Kotlin no dia a dia, talvez sem saber:\nGradle Kotlin DSL: build.gradle.kts inteiro é uma DSL Ktor: configuração de servidor e rotas Jetpack Compose: toda a UI é uma DSL Exposed: queries SQL type-safe Kotest: framework de testes com DSL expressiva Koin: injeção de dependência com DSL Boas práticas Menos é mais: uma DSL boa é simples e focada Use @DslMarker: em DSLs aninhadas, controle o escopo Documente os builders: quem usa sua DSL precisa saber o que está disponível Valide no build: se algo obrigatório está faltando, falhe cedo com mensagem clara Teste a DSL: garanta que o código gerado está correto Conclusão DSLs são a cereja do bolo do Kotlin. Elas permitem criar APIs que lêem como documentação, são verificadas pelo compilador e proporcionam uma experiência de uso excepcional. Dominar lambdas com receiver e apply/with/run é a chave para desbloquear esse superpoder.\nAgora é com você: pense num domínio do seu projeto que se beneficiaria de uma DSL e mãos à obra! Cada linguagem tem seus próprios mecanismos para DSLs — Rust usa macros procedurais e Python aproveita decorators e metaclasses.\n","permalink":"https://kotlin.dev.br/blog/kotlin-dsl/","summary":"\u003cp\u003eSe você já usou Gradle com Kotlin, configurou rotas no Ktor ou montou layouts no Jetpack Compose, você já usou uma DSL sem perceber. DSL (Domain Specific Language) é um dos recursos mais elegantes de Kotlin, e neste post vamos entender como criar as nossas próprias.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-uma-dsl\"\u003eO que é uma DSL?\u003c/h2\u003e\n\u003cp\u003eUma DSL é uma mini-linguagem projetada para um domínio específico. Diferente de uma linguagem de propósito geral (como Kotlin ou Java), uma DSL foca em resolver problemas de uma área particular de forma expressiva.\u003c/p\u003e","title":"DSL em Kotlin: Como Criar e Usar | Kotlin Brasil"},{"content":"Sobre a vagaBuscamos um Engenheiro de Software Senior experiente em Flutter para integrar o time de Digital Equities do BTG Pactual. Você atuará em projetos mobile de alta relevância, trabalhando com arquitetura robusta, testes e metodologias ágeis.\nResponsabilidadesDesenvolver e manter aplicações mobile usando Flutter com foco em qualidade e performanceImplementar arquitetura escalável com padrões reconhecidosTrabalhar com APIs REST e WebSockets para integração de dados em tempo realContribuir para a definição e evolução de padrões de código e arquiteturaParticipar de code reviews e mentorar membros do timeRequisitosExperiência sênior comprovada em desenvolvimento mobile com FlutterConhecimento sólido em Kotlin e/ou SwiftDomínio de padrões arquiteturais e boas práticas de desenvolvimentoExperiência com REST APIs e WebSocketsProficiência em testes (unitários, de integração e end-to-end)Familiaridade com metodologias ágeisExperiência com state management (MobX, ChangeNotifier ou equivalentes) ","permalink":"https://kotlin.dev.br/vagas/w9jnw9muqsvs9bd0-btg-pactual-engenheiro-de-software-senior-flutter/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eBuscamos um Engenheiro de Software Senior experiente em Flutter para integrar o time de Digital Equities do BTG Pactual. Você atuará em projetos mobile de alta relevância, trabalhando com arquitetura robusta, testes e metodologias ágeis.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações mobile usando Flutter com foco em qualidade e performance\u003c/li\u003e\u003cli\u003eImplementar arquitetura escalável com padrões reconhecidos\u003c/li\u003e\u003cli\u003eTrabalhar com APIs REST e WebSockets para integração de dados em tempo real\u003c/li\u003e\u003cli\u003eContribuir para a definição e evolução de padrões de código e arquitetura\u003c/li\u003e\u003cli\u003eParticipar de code reviews e mentorar membros do time\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior comprovada em desenvolvimento mobile com Flutter\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin e/ou Swift\u003c/li\u003e\u003cli\u003eDomínio de padrões arquiteturais e boas práticas de desenvolvimento\u003c/li\u003e\u003cli\u003eExperiência com REST APIs e WebSockets\u003c/li\u003e\u003cli\u003eProficiência em testes (unitários, de integração e end-to-end)\u003c/li\u003e\u003cli\u003eFamiliaridade com metodologias ágeis\u003c/li\u003e\u003cli\u003eExperiência com state management (MobX, ChangeNotifier ou equivalentes)\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Software Senior - Flutter"},{"content":"Escrever o mesmo código duas (ou três) vezes para plataformas diferentes é uma dor que todo time de desenvolvimento conhece. Kotlin Multiplatform (KMP) resolve isso permitindo compartilhar lógica de negócio entre Android, iOS, web e backend — tudo em Kotlin. Vamos entender como funciona.\nO que é Kotlin Multiplatform? Kotlin Multiplatform é uma tecnologia da JetBrains que permite escrever código uma vez e usar em múltiplas plataformas. Diferente de soluções como Flutter ou React Native, o KMP não substitui a UI nativa — ele compartilha a lógica de negócio enquanto cada plataforma mantém sua interface nativa.\nIsso significa:\nAndroid: UI com Jetpack Compose, lógica compartilhada em Kotlin iOS: UI com SwiftUI, lógica compartilhada em Kotlin (compilado para framework nativo) Web: UI com frameworks JS/Kotlin, lógica compartilhada Backend: mesmos modelos e regras de negócio do app Por que KMP e não Flutter/React Native? Cada abordagem tem seus méritos, mas o KMP se destaca por:\nUI nativa real: a interface de cada plataforma usa os componentes nativos Adoção gradual: você pode integrar KMP em projetos existentes Performance nativa: sem bridge, sem overhead de runtime Flexibilidade: compartilhe só o que faz sentido — de 20% a 80% do código Kotlin: uma das linguagens mais amadas pelos desenvolvedores Estrutura de um projeto KMP Um projeto KMP típico é organizado assim:\nmeu-app/ ├── shared/ # Módulo compartilhado │ └── src/ │ ├── commonMain/ # Código comum a todas as plataformas │ ├── commonTest/ # Testes compartilhados │ ├── androidMain/ # Código especifico Android │ ├── iosMain/ # Código especifico iOS │ └── jvmMain/ # Código especifico JVM (backend) ├── androidApp/ # Aplicativo Android ├── iosApp/ # Aplicativo iOS (projeto Xcode) └── build.gradle.kts Configurando o projeto O build.gradle.kts do módulo compartilhado:\nplugins { kotlin(\u0026#34;multiplatform\u0026#34;) id(\u0026#34;com.android.library\u0026#34;) kotlin(\u0026#34;plugin.serialization\u0026#34;) } kotlin { androidTarget() iosX64() iosArm64() iosSimulatorArm64() jvm() sourceSets { commonMain.dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0\u0026#34;) implementation(\u0026#34;io.ktor:ktor-client-core:3.0.0\u0026#34;) implementation(\u0026#34;io.ktor:ktor-client-content-negotiation:3.0.0\u0026#34;) implementation(\u0026#34;io.ktor:ktor-serialization-kotlinx-json:3.0.0\u0026#34;) } androidMain.dependencies { implementation(\u0026#34;io.ktor:ktor-client-android:3.0.0\u0026#34;) } iosMain.dependencies { implementation(\u0026#34;io.ktor:ktor-client-darwin:3.0.0\u0026#34;) } jvmMain.dependencies { implementation(\u0026#34;io.ktor:ktor-client-cio:3.0.0\u0026#34;) } } } Código compartilhado: modelos e regras de negócio Tudo que vai em commonMain é compartilhado entre todas as plataformas:\n// commonMain/kotlin/model/Produto.kt @Serializable data class Produto( val id: Long, val nome: String, val descricao: String, val preco: Double, val imagemUrl: String ) // commonMain/kotlin/model/Carrinho.kt data class Carrinho( val itens: List\u0026lt;ItemCarrinho\u0026gt; = emptyList() ) { val total: Double get() = itens.sumOf { it.produto.preco * it.quantidade } val quantidadeTotal: Int get() = itens.sumOf { it.quantidade } fun adicionar(produto: Produto, quantidade: Int = 1): Carrinho { val existente = itens.find { it.produto.id == produto.id } return if (existente != null) { copy(itens = itens.map { if (it.produto.id == produto.id) it.copy(quantidade = it.quantidade + quantidade) else it }) } else { copy(itens = itens + ItemCarrinho(produto, quantidade)) } } fun remover(produtoId: Long): Carrinho { return copy(itens = itens.filter { it.produto.id != produtoId }) } } data class ItemCarrinho(val produto: Produto, val quantidade: Int) Esse código roda igualzinho no Android, no iOS e no backend. Escreva uma vez, teste uma vez, use em todo lugar.\nChamadas de rede compartilhadas Usando Ktor Client, as chamadas de API ficam no código comum:\n// commonMain/kotlin/api/ProdutoApi.kt class ProdutoApi(private val client: HttpClient) { suspend fun buscarProdutos(): List\u0026lt;Produto\u0026gt; { return client.get(\u0026#34;https://api.meuapp.com.br/produtos\u0026#34;) .body\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt;() } suspend fun buscarProduto(id: Long): Produto { return client.get(\u0026#34;https://api.meuapp.com.br/produtos/$id\u0026#34;) .body\u0026lt;Produto\u0026gt;() } } // commonMain/kotlin/api/HttpClientFactory.kt fun criarHttpClient() = HttpClient { install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true isLenient = true }) } } expect/actual: código específico por plataforma Quando você precisa de algo específico de cada plataforma, usa o mecanismo expect/actual:\n// commonMain — declaração expect (como uma interface) expect fun plataformaAtual(): String expect class ArmazenamentoLocal { fun salvar(chave: String, valor: String) fun ler(chave: String): String? } // androidMain — implementacao actual actual fun plataformaAtual(): String = \u0026#34;Android ${Build.VERSION.SDK_INT}\u0026#34; actual class ArmazenamentoLocal(context: Context) { private val prefs = context.getSharedPreferences(\u0026#34;app\u0026#34;, Context.MODE_PRIVATE) actual fun salvar(chave: String, valor: String) { prefs.edit().putString(chave, valor).apply() } actual fun ler(chave: String): String? = prefs.getString(chave, null) } // iosMain — implementacao actual actual fun plataformaAtual(): String = \u0026#34;iOS ${UIDevice.currentDevice.systemVersion}\u0026#34; actual class ArmazenamentoLocal { private val defaults = NSUserDefaults.standardUserDefaults actual fun salvar(chave: String, valor: String) { defaults.setObject(valor, forKey = chave) } actual fun ler(chave: String): String? = defaults.stringForKey(chave) } ViewModel compartilhado Com KMP, até a camada de ViewModel pode ser compartilhada:\n// commonMain/kotlin/viewmodel/ProdutoListViewModel.kt class ProdutoListViewModel(private val api: ProdutoApi) { private val _state = MutableStateFlow\u0026lt;ProdutoListState\u0026gt;(ProdutoListState.Carregando) val state: StateFlow\u0026lt;ProdutoListState\u0026gt; = _state.asStateFlow() private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob()) fun carregar() { scope.launch { _state.value = ProdutoListState.Carregando try { val produtos = api.buscarProdutos() _state.value = ProdutoListState.Sucesso(produtos) } catch (e: Exception) { _state.value = ProdutoListState.Erro(e.message ?: \u0026#34;Erro desconhecido\u0026#34;) } } } fun limpar() { scope.cancel() } } sealed class ProdutoListState { data object Carregando : ProdutoListState() data class Sucesso(val produtos: List\u0026lt;Produto\u0026gt;) : ProdutoListState() data class Erro(val mensagem: String) : ProdutoListState() } Usando no iOS (SwiftUI) O código Kotlin compartilhado é acessado no Swift de forma transparente:\n// Exemplo de como fica no SwiftUI (pseudo-codigo para contexto): // struct ProdutoListView: View { // @StateObject var viewModel = ProdutoListViewModel(api: ProdutoApi(...)) // // var body: some View { // switch viewModel.state { // case .carregando: ProgressView() // case .sucesso(let produtos): List(produtos) { ... } // case .erro(let msg): Text(msg) // } // } // } Compose Multiplatform Para quem quer compartilhar até a UI, existe o Compose Multiplatform — Jetpack Compose que roda em Android, iOS, Desktop e Web:\n@Composable fun ProdutoCard(produto: Produto, onClicar: () -\u0026gt; Unit) { Card( modifier = Modifier .fillMaxWidth() .padding(8.dp) .clickable { onClicar() } ) { Column(modifier = Modifier.padding(16.dp)) { Text(produto.nome, style = MaterialTheme.typography.titleMedium) Text(produto.descricao, style = MaterialTheme.typography.bodyMedium) Text( \u0026#34;R$ ${\u0026#34;%.2f\u0026#34;.format(produto.preco)}\u0026#34;, style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.primary ) } } } Esse composable roda em todas as plataformas!\nConclusão Kotlin Multiplatform é a aposta mais promissora para compartilhamento de código entre plataformas em 2026. A abordagem incremental, o respeito pela UI nativa e a maturidade crescente do ecossistema fazem do KMP uma escolha cada vez mais segura para times de todos os tamanhos.\nComece pelo módulo de modelos e regras de negócio, vá expandindo aos poucos, e veja a produtividade do seu time decolar. Outras abordagens cross-platform incluem Rust via WebAssembly e Go com gomobile. O futuro é multiplataforma — e é em Kotlin!\n","permalink":"https://kotlin.dev.br/blog/kotlin-multiplatform/","summary":"\u003cp\u003eEscrever o mesmo código duas (ou três) vezes para plataformas diferentes é uma dor que todo time de desenvolvimento conhece. Kotlin Multiplatform (KMP) resolve isso permitindo compartilhar lógica de negócio entre Android, iOS, web e backend — tudo em Kotlin. Vamos entender como funciona.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-kotlin-multiplatform\"\u003eO que é Kotlin Multiplatform?\u003c/h2\u003e\n\u003cp\u003eKotlin Multiplatform é uma tecnologia da JetBrains que permite escrever código uma vez e usar em múltiplas plataformas. Diferente de soluções como Flutter ou React Native, o KMP \u003cstrong\u003enão substitui a UI nativa\u003c/strong\u003e — ele compartilha a lógica de negócio enquanto cada plataforma mantém sua interface nativa.\u003c/p\u003e","title":"Kotlin Multiplatform: Guia Completo em Português | Kotlin Brasil"},{"content":"Spring Boot é o framework mais popular do ecossistema Java para backend, e ele funciona maravilhosamente bem com Kotlin. Na verdade, a combinação Kotlin + Spring Boot é tão boa que a equipe do Spring tem suporte oficial e dedicado à linguagem. Vamos construir uma API REST do zero neste tutorial.\nPor que Kotlin com Spring Boot? A pergunta melhor seria: por que não? Kotlin traz benefícios concretos para projetos Spring Boot:\nMenos boilerplate: data classes, default parameters, extension functions Null Safety: menos bugs em runtime Coroutines: suporte nativo para programação reativa com WebFlux DSLs: configurações declarativas e elegantes Suporte oficial: a equipe do Spring mantém integração de primeira classe Criando o projeto Acesse o Spring Initializr e selecione:\nLanguage: Kotlin Build tool: Gradle - Kotlin Dependencies: Spring Web, Spring Data JPA, H2 Database, Spring Validation Ou configure manualmente o build.gradle.kts:\nplugins { id(\u0026#34;org.springframework.boot\u0026#34;) version \u0026#34;3.4.0\u0026#34; id(\u0026#34;io.spring.dependency-management\u0026#34;) version \u0026#34;1.1.6\u0026#34; kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.1.0\u0026#34; kotlin(\u0026#34;plugin.spring\u0026#34;) version \u0026#34;2.1.0\u0026#34; kotlin(\u0026#34;plugin.jpa\u0026#34;) version \u0026#34;2.1.0\u0026#34; } dependencies { implementation(\u0026#34;org.springframework.boot:spring-boot-starter-web\u0026#34;) implementation(\u0026#34;org.springframework.boot:spring-boot-starter-data-jpa\u0026#34;) implementation(\u0026#34;org.springframework.boot:spring-boot-starter-validation\u0026#34;) implementation(\u0026#34;com.fasterxml.jackson.module:jackson-module-kotlin\u0026#34;) runtimeOnly(\u0026#34;com.h2database:h2\u0026#34;) testImplementation(\u0026#34;org.springframework.boot:spring-boot-starter-test\u0026#34;) } Os plugins plugin.spring e plugin.jpa são essenciais: eles geram construtores sem argumentos e abrem classes automaticamente (Spring precisa disso para proxies).\nDefinindo a entidade @Entity @Table(name = \u0026#34;produtos\u0026#34;) data class Produto( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0, @field:NotBlank(message = \u0026#34;Nome e obrigatorio\u0026#34;) val nome: String, @field:Size(max = 500, message = \u0026#34;Descrição deve ter no máximo 500 caracteres\u0026#34;) val descricao: String = \u0026#34;\u0026#34;, @field:Positive(message = \u0026#34;Preço deve ser positivo\u0026#34;) val preco: BigDecimal, @field:PositiveOrZero(message = \u0026#34;Estoque nao pode ser negativo\u0026#34;) val estoque: Int = 0, val ativo: Boolean = true ) Repare nos valores padrão — isso elimina a necessidade de múltiplos construtores.\nRepositório Com Spring Data JPA, o repositório é simples assim:\n@Repository interface ProdutoRepository : JpaRepository\u0026lt;Produto, Long\u0026gt; { fun findByAtivoTrue(): List\u0026lt;Produto\u0026gt; fun findByNomeContainingIgnoreCase(nome: String): List\u0026lt;Produto\u0026gt; fun findByPrecoLessThanEqual(precoMaximo: BigDecimal): List\u0026lt;Produto\u0026gt; } Sem implementação necessária — o Spring gera tudo automaticamente a partir dos nomes dos métodos.\nDTOs com data class Use data classes para separar a camada de transporte da entidade:\ndata class ProdutoRequest( @field:NotBlank(message = \u0026#34;Nome e obrigatorio\u0026#34;) val nome: String, val descricao: String = \u0026#34;\u0026#34;, @field:Positive(message = \u0026#34;Preço deve ser positivo\u0026#34;) val preco: BigDecimal, val estoque: Int = 0 ) data class ProdutoResponse( val id: Long, val nome: String, val descricao: String, val preco: BigDecimal, val estoque: Int, val ativo: Boolean ) fun Produto.toResponse() = ProdutoResponse( id = id, nome = nome, descricao = descricao, preco = preco, estoque = estoque, ativo = ativo ) A extension function toResponse() é o jeito Kotlin de fazer mapeamento entre entidade e DTO sem precisar de bibliotecas como MapStruct.\nService @Service class ProdutoService(private val repository: ProdutoRepository) { fun listarTodos(): List\u0026lt;ProdutoResponse\u0026gt; = repository.findByAtivoTrue().map { it.toResponse() } fun buscarPorId(id: Long): ProdutoResponse = repository.findByIdOrNull(id)?.toResponse() ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, \u0026#34;Produto nao encontrado\u0026#34;) fun buscarPorNome(nome: String): List\u0026lt;ProdutoResponse\u0026gt; = repository.findByNomeContainingIgnoreCase(nome).map { it.toResponse() } @Transactional fun criar(request: ProdutoRequest): ProdutoResponse { val produto = Produto( nome = request.nome, descricao = request.descricao, preco = request.preco, estoque = request.estoque ) return repository.save(produto).toResponse() } @Transactional fun atualizar(id: Long, request: ProdutoRequest): ProdutoResponse { val existente = repository.findByIdOrNull(id) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, \u0026#34;Produto nao encontrado\u0026#34;) val atualizado = existente.copy( nome = request.nome, descricao = request.descricao, preco = request.preco, estoque = request.estoque ) return repository.save(atualizado).toResponse() } @Transactional fun deletar(id: Long) { val produto = repository.findByIdOrNull(id) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, \u0026#34;Produto nao encontrado\u0026#34;) repository.save(produto.copy(ativo = false)) // soft delete } } Veja como o copy() da data class facilita a atualização: criamos uma nova instância alterando só o que mudou.\nController @RestController @RequestMapping(\u0026#34;/api/produtos\u0026#34;) class ProdutoController(private val service: ProdutoService) { @GetMapping fun listarTodos() = service.listarTodos() @GetMapping(\u0026#34;/{id}\u0026#34;) fun buscarPorId(@PathVariable id: Long) = service.buscarPorId(id) @GetMapping(\u0026#34;/busca\u0026#34;) fun buscarPorNome(@RequestParam nome: String) = service.buscarPorNome(nome) @PostMapping @ResponseStatus(HttpStatus.CREATED) fun criar(@Valid @RequestBody request: ProdutoRequest) = service.criar(request) @PutMapping(\u0026#34;/{id}\u0026#34;) fun atualizar( @PathVariable id: Long, @Valid @RequestBody request: ProdutoRequest ) = service.atualizar(id, request) @DeleteMapping(\u0026#34;/{id}\u0026#34;) @ResponseStatus(HttpStatus.NO_CONTENT) fun deletar(@PathVariable id: Long) = service.deletar(id) } Tratamento global de erros @RestControllerAdvice class GlobalExceptionHandler { data class ErroResponse( val status: Int, val mensagem: String, val timestamp: LocalDateTime = LocalDateTime.now() ) @ExceptionHandler(ResponseStatusException::class) fun handleResponseStatus(ex: ResponseStatusException): ResponseEntity\u0026lt;ErroResponse\u0026gt; { val erro = ErroResponse( status = ex.statusCode.value(), mensagem = ex.reason ?: \u0026#34;Erro desconhecido\u0026#34; ) return ResponseEntity.status(ex.statusCode).body(erro) } @ExceptionHandler(MethodArgumentNotValidException::class) fun handleValidation(ex: MethodArgumentNotValidException): ResponseEntity\u0026lt;ErroResponse\u0026gt; { val mensagens = ex.bindingResult.fieldErrors.joinToString(\u0026#34;; \u0026#34;) { \u0026#34;${it.field}: ${it.defaultMessage}\u0026#34; } val erro = ErroResponse(status = 400, mensagem = mensagens) return ResponseEntity.badRequest().body(erro) } } Testando a API Com Spring Boot Test e Kotlin, os testes ficam bem expressivos:\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class ProdutoControllerTest(@Autowired val restTemplate: TestRestTemplate) { @Test fun `deve criar produto com sucesso`() { val request = ProdutoRequest( nome = \u0026#34;Teclado Mecânico\u0026#34;, descricao = \u0026#34;Switch Cherry MX Blue\u0026#34;, preco = BigDecimal(\u0026#34;349.90\u0026#34;), estoque = 50 ) val response = restTemplate.postForEntity( \u0026#34;/api/produtos\u0026#34;, request, ProdutoResponse::class.java ) assertThat(response.statusCode).isEqualTo(HttpStatus.CREATED) assertThat(response.body?.nome).isEqualTo(\u0026#34;Teclado Mecânico\u0026#34;) assertThat(response.body?.id).isGreaterThan(0) } } Kotlin permite usar crases nos nomes dos testes, o que deixa a descrição muito mais legível.\nConclusão Kotlin e Spring Boot formam uma dupla espetacular para backend. Você tem toda a maturidade e estabilidade do ecossistema Spring com a expressividade e segurança de Kotlin. Se você já conhece Spring com Java, a transição para Kotlin é suavíssima — e os ganhos em produtividade aparecem logo nas primeiras linhas de código. Para comparar com outras abordagens de backend, veja como Go constrói APIs REST com net/http e Gin ou como Python faz o mesmo com FastAPI e Django.\nMonta seu projeto e bora codar!\n","permalink":"https://kotlin.dev.br/blog/kotlin-spring-boot/","summary":"\u003cp\u003eSpring Boot é o framework mais popular do ecossistema Java para backend, e ele funciona maravilhosamente bem com Kotlin. Na verdade, a combinação Kotlin + Spring Boot é tão boa que a equipe do Spring tem suporte oficial e dedicado à linguagem. Vamos construir uma API REST do zero neste tutorial.\u003c/p\u003e\n\u003ch2 id=\"por-que-kotlin-com-spring-boot\"\u003ePor que Kotlin com Spring Boot?\u003c/h2\u003e\n\u003cp\u003eA pergunta melhor seria: por que não? Kotlin traz benefícios concretos para projetos Spring Boot:\u003c/p\u003e","title":"Kotlin com Spring Boot: Tutorial Passo a Passo | Kotlin Brasil"},{"content":"Se você já precisou representar um conjunto finito de estados ou tipos no seu código, as Sealed Classes do Kotlin são exatamente o que você procura. Elas combinam o melhor dos enums com a flexibilidade das classes, é o compilador ainda te ajuda a não esquecer nenhum caso. Bora entender!\nO que são Sealed Classes? Uma sealed class é uma classe abstrata que restringe quais subclasses podem existir. Todas as subclasses devem ser definidas no mesmo pacote (e normalmente no mesmo arquivo). Isso dá ao compilador a garantia de que ele conhece todos os tipos possíveis.\nsealed class Resultado { data class Sucesso(val dados: String) : Resultado() data class Erro(val mensagem: String, val codigo: Int) : Resultado() data object Carregando : Resultado() } Por que não usar Enum? Enums são ótimos, mas têm uma limitação: cada valor é uma instância única. Você não pode ter dados diferentes em cada instância:\n// Enum — cada valor é fixo enum class Status { SUCESSO, ERRO, CARREGANDO } // Como associar uma mensagem de erro ao Status.ERRO? Complicado. // Sealed Class — cada subclasse pode ter seus próprios dados sealed class Status { data class Sucesso(val dados: List\u0026lt;Item\u0026gt;) : Status() data class Erro(val exception: Throwable) : Status() data object Carregando : Status() } O poder do when exaustivo A grande sacada das sealed classes é que o compilador sabe todas as subclasses. Quando você usa when, ele garante que todos os casos estão cobertos:\nfun exibirStatus(status: Status): String = when (status) { is Status.Sucesso -\u0026gt; \u0026#34;Carregou ${status.dados.size} itens\u0026#34; is Status.Erro -\u0026gt; \u0026#34;Erro: ${status.exception.message}\u0026#34; is Status.Carregando -\u0026gt; \u0026#34;Carregando...\u0026#34; // Sem `else` necessario! O compilador sabe que cobriu tudo. } Se amanhã você adicionar um novo subtipo (digamos, Status.SemConexao), o compilador vai apontar erro em todos os when que não tratam esse novo caso. Isso é poderosíssimo para evitar bugs.\nCaso prático: resultado de chamada de API Esse é o uso mais clássico de sealed classes no desenvolvimento Android e backend:\nsealed class ApiResult\u0026lt;out T\u0026gt; { data class Success\u0026lt;T\u0026gt;(val data: T) : ApiResult\u0026lt;T\u0026gt;() data class Error(val message: String, val code: Int? = null) : ApiResult\u0026lt;Nothing\u0026gt;() data object Loading : ApiResult\u0026lt;Nothing\u0026gt;() } class UsuarioRepository(private val api: ApiService) { suspend fun buscarUsuario(id: Int): ApiResult\u0026lt;Usuario\u0026gt; { return try { val usuario = api.getUsuario(id) ApiResult.Success(usuario) } catch (e: HttpException) { ApiResult.Error(\u0026#34;Erro HTTP: ${e.code()}\u0026#34;, e.code()) } catch (e: Exception) { ApiResult.Error(\u0026#34;Falha na conexão: ${e.message}\u0026#34;) } } } // No ViewModel fun carregarUsuario(id: Int) { viewModelScope.launch { _uiState.value = ApiResult.Loading when (val resultado = repository.buscarUsuario(id)) { is ApiResult.Success -\u0026gt; _uiState.value = UiState.Dados(resultado.data) is ApiResult.Error -\u0026gt; _uiState.value = UiState.Erro(resultado.message) is ApiResult.Loading -\u0026gt; { /* já tratado acima */ } } } } Sealed classes para navegação Definir rotas de navegação com sealed classes é um padrão muito usado em apps Android:\nsealed class Tela(val rota: String) { data object Inicio : Tela(\u0026#34;inicio\u0026#34;) data object ListaProdutos : Tela(\u0026#34;produtos\u0026#34;) data class DetalhesProduto(val id: Int) : Tela(\u0026#34;produtos/$id\u0026#34;) data class Perfil(val userId: String) : Tela(\u0026#34;perfil/$userId\u0026#34;) data object Configurações : Tela(\u0026#34;configurações\u0026#34;) } fun navegar(tela: Tela, navController: NavController) { when (tela) { is Tela.Inicio -\u0026gt; navController.navigate(tela.rota) is Tela.ListaProdutos -\u0026gt; navController.navigate(tela.rota) is Tela.DetalhesProduto -\u0026gt; navController.navigate(tela.rota) is Tela.Perfil -\u0026gt; navController.navigate(tela.rota) is Tela.Configurações -\u0026gt; navController.navigate(tela.rota) } } Sealed interfaces A partir do Kotlin 1.5, temos também sealed interfaces, que são ainda mais flexíveis pois uma classe pode implementar múltiplas sealed interfaces:\nsealed interface Evento sealed interface EventoDeUsuario : Evento { data class Login(val email: String) : EventoDeUsuario data class Logout(val motivo: String) : EventoDeUsuario data class AlterarPerfil(val campo: String, val valor: String) : EventoDeUsuario } sealed interface EventoDeSistema : Evento { data class ErroDeRede(val codigo: Int) : EventoDeSistema data object ConexaoRestabelecida : EventoDeSistema } fun tratarEvento(evento: Evento) = when (evento) { is EventoDeUsuario.Login -\u0026gt; println(\u0026#34;Usuário logou: ${evento.email}\u0026#34;) is EventoDeUsuario.Logout -\u0026gt; println(\u0026#34;Logout: ${evento.motivo}\u0026#34;) is EventoDeUsuario.AlterarPerfil -\u0026gt; println(\u0026#34;Alterou ${evento.campo}\u0026#34;) is EventoDeSistema.ErroDeRede -\u0026gt; println(\u0026#34;Erro de rede: ${evento.codigo}\u0026#34;) is EventoDeSistema.ConexaoRestabelecida -\u0026gt; println(\u0026#34;Conexão OK!\u0026#34;) } Modelando máquinas de estado Sealed classes são perfeitas para máquinas de estado:\nsealed class EstadoPedido { data object Criado : EstadoPedido() data class AguardandoPagamento(val valorTotal: Double) : EstadoPedido() data class Pago(val transacaoId: String) : EstadoPedido() data class EmSeparacao(val previsaoDespacho: LocalDate) : EstadoPedido() data class Enviado(val codigoRastreio: String) : EstadoPedido() data object Entregue : EstadoPedido() data class Cancelado(val motivo: String) : EstadoPedido() } fun proximaAcao(estado: EstadoPedido): String = when (estado) { is EstadoPedido.Criado -\u0026gt; \u0026#34;Aguardar pagamento\u0026#34; is EstadoPedido.AguardandoPagamento -\u0026gt; \u0026#34;Pagar R$ ${estado.valorTotal}\u0026#34; is EstadoPedido.Pago -\u0026gt; \u0026#34;Transação ${estado.transacaoId} confirmada. Separar produtos.\u0026#34; is EstadoPedido.EmSeparacao -\u0026gt; \u0026#34;Despacho previsto: ${estado.previsaoDespacho}\u0026#34; is EstadoPedido.Enviado -\u0026gt; \u0026#34;Rastrear: ${estado.codigoRastreio}\u0026#34; is EstadoPedido.Entregue -\u0026gt; \u0026#34;Avaliar compra\u0026#34; is EstadoPedido.Cancelado -\u0026gt; \u0026#34;Pedido cancelado: ${estado.motivo}\u0026#34; } Sealed class vs sealed interface: quando usar qual? Use sealed class quando as subclasses compartilham estado ou comportamento comum Use sealed interface quando quer mais flexibilidade com múltipla implementação Na dúvida, comece com sealed class — é mais simples de refatorar depois Boas práticas Use sealed classes para estados de UI: Loading, Success, Error — o padrão clássico Prefira data class e data object para as subclasses — você ganha toString(), equals() e copy() de graça Evite else no when: perca o hábito de usar else com sealed classes; assim o compilador te avisa quando um novo caso não foi tratado Mantenha as subclasses simples: se uma subclasse está ficando complexa demais, talvez ela precise ser outra sealed class Conclusão Sealed Classes são um daqueles recursos que, depois que você começa a usar, não volta mais atrás. Elas tornam seu código mais seguro, mais expressivo e mais fácil de manter. O compilador vira seu aliado, garantindo que você nunca esqueça de tratar um caso. Um conceito similar existe em Rust com enums e pattern matching, que também garante exaustividade em tempo de compilação.\nSe você quer escrever Kotlin idiomático, dominar sealed classes é obrigatório. Mãos à obra!\n","permalink":"https://kotlin.dev.br/blog/sealed-classes-kotlin/","summary":"\u003cp\u003eSe você já precisou representar um conjunto finito de estados ou tipos no seu código, as Sealed Classes do Kotlin são exatamente o que você procura. Elas combinam o melhor dos enums com a flexibilidade das classes, é o compilador ainda te ajuda a não esquecer nenhum caso. Bora entender!\u003c/p\u003e\n\u003ch2 id=\"o-que-são-sealed-classes\"\u003eO que são Sealed Classes?\u003c/h2\u003e\n\u003cp\u003eUma sealed class é uma classe abstrata que restringe quais subclasses podem existir. Todas as subclasses devem ser definidas no mesmo pacote (e normalmente no mesmo arquivo). Isso dá ao compilador a garantia de que ele conhece todos os tipos possíveis.\u003c/p\u003e","title":"Sealed Classes em Kotlin: O que São e Como Usar | Kotlin Brasil"},{"content":"Imagine poder adicionar métodos novos a classes que já existem — sem herança, sem wrappers, sem modificar o código original. Parece mágica? Em Kotlin, isso se chama Extension Functions, e é um dos recursos mais queridos da linguagem.\nO que são Extension Functions? Extension Functions permitem que você \u0026ldquo;estenda\u0026rdquo; uma classe com novas funções, como se elas fizessem parte da classe original. A sintaxe é simples:\nfun String.contarPalavras(): Int { return this.trim().split(\u0026#34;\\\\s+\u0026#34;.toRegex()).size } fun main() { val frase = \u0026#34;Kotlin é incrível demais da conta\u0026#34; println(frase.contarPalavras()) // 6 } Repare: contarPalavras() não existe na classe String, mas a gente chamou como se existisse. O this dentro da função refere-se ao objeto receptor (no caso, a String).\nExemplos práticos do dia a dia Vamos ver extensões que você vai querer copiar agora mesmo pro seu projeto:\nFormatação de valores brasileiros fun Double.toBRL(): String { return \u0026#34;R$ %,.2f\u0026#34;.format(this).replace(\u0026#34;,\u0026#34;, \u0026#34;X\u0026#34;).replace(\u0026#34;.\u0026#34;, \u0026#34;,\u0026#34;).replace(\u0026#34;X\u0026#34;, \u0026#34;.\u0026#34;) } fun String.toCpfFormatado(): String { val limpo = this.replace(\u0026#34;[^0-9]\u0026#34;.toRegex(), \u0026#34;\u0026#34;) require(limpo.length == 11) { \u0026#34;CPF deve ter 11 dígitos\u0026#34; } return \u0026#34;${limpo.substring(0,3)}.${limpo.substring(3,6)}.${limpo.substring(6,9)}-${limpo.substring(9)}\u0026#34; } fun String.toCnpjFormatado(): String { val limpo = this.replace(\u0026#34;[^0-9]\u0026#34;.toRegex(), \u0026#34;\u0026#34;) require(limpo.length == 14) { \u0026#34;CNPJ deve ter 14 dígitos\u0026#34; } return \u0026#34;${limpo.substring(0,2)}.${limpo.substring(2,5)}.${limpo.substring(5,8)}/${limpo.substring(8,12)}-${limpo.substring(12)}\u0026#34; } fun main() { println(1499.90.toBRL()) // R$ 1.499,90 println(\u0026#34;12345678901\u0026#34;.toCpfFormatado()) // 123.456.789-01 println(\u0026#34;12345678000190\u0026#34;.toCnpjFormatado()) // 12.345.678/0001-90 } Validações fun String.isEmailValido(): Boolean { return matches(\u0026#34;[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}\u0026#34;.toRegex()) } fun String.isCpfValido(): Boolean { val numeros = this.replace(\u0026#34;[^0-9]\u0026#34;.toRegex(), \u0026#34;\u0026#34;) if (numeros.length != 11) return false if (numeros.all { it == numeros[0] }) return false // Validação dos dígitos verificadores val dv1 = (0..8).sumOf { (10 - it) * numeros[it].digitToInt() } % 11 val primeiroDigito = if (dv1 \u0026lt; 2) 0 else 11 - dv1 val dv2 = (0..9).sumOf { (11 - it) * numeros[it].digitToInt() } % 11 val segundoDigito = if (dv2 \u0026lt; 2) 0 else 11 - dv2 return numeros[9].digitToInt() == primeiroDigito \u0026amp;\u0026amp; numeros[10].digitToInt() == segundoDigito } fun main() { println(\u0026#34;karina@kotlin.dev.br\u0026#34;.isEmailValido()) // true println(\u0026#34;email-invalido\u0026#34;.isEmailValido()) // false } Manipulação de datas import java.time.LocalDate import java.time.format.DateTimeFormatter import java.time.Period fun LocalDate.toBrazilianFormat(): String { return this.format(DateTimeFormatter.ofPattern(\u0026#34;dd/MM/yyyy\u0026#34;)) } fun LocalDate.idadeEmAnos(): Int { return Period.between(this, LocalDate.now()).years } fun main() { val nascimento = LocalDate.of(1995, 6, 15) println(nascimento.toBrazilianFormat()) // 15/06/1995 println(\u0026#34;Idade: ${nascimento.idadeEmAnos()} anos\u0026#34;) } Extension Properties Não é só função — você também pode criar propriedades de extensão:\nval String.primeiraLetra: Char get() = this.first() val String.ultimaLetra: Char get() = this.last() val List\u0026lt;*\u0026gt;.penultimoElemento: Any? get() = this[this.size - 2] fun main() { println(\u0026#34;Kotlin\u0026#34;.primeiraLetra) // K println(\u0026#34;Kotlin\u0026#34;.ultimaLetra) // n } Uma limitação importante: extension properties não podem ter backing field, ou seja, não podem armazenar estado. Elas sempre precisam ser calculadas.\nExtensions em coleções Extensões brilham quando trabalham com coleções:\nfun \u0026lt;T\u0026gt; List\u0026lt;T\u0026gt;.segundoOuNull(): T? = if (this.size \u0026gt;= 2) this[1] else null fun List\u0026lt;Int\u0026gt;.mediana(): Double { val ordenada = this.sorted() val meio = ordenada.size / 2 return if (ordenada.size % 2 == 0) { (ordenada[meio - 1] + ordenada[meio]) / 2.0 } else { ordenada[meio].toDouble() } } fun \u0026lt;T\u0026gt; List\u0026lt;T\u0026gt;.agruparEmPares(): List\u0026lt;Pair\u0026lt;T, T?\u0026gt;\u0026gt; { return this.chunked(2).map { chunk -\u0026gt; Pair(chunk[0], chunk.getOrNull(1)) } } fun main() { val numeros = listOf(3, 1, 4, 1, 5, 9, 2, 6) println(numeros.mediana()) // 3.5 println(numeros.segundoOuNull()) // 1 println(numeros.agruparEmPares()) // [(3, 1), (4, 1), (5, 9), (2, 6)] } Como funciona por baixo dos panos É importante entender: extension functions não modificam realmente a classe. Elas são resolvidas estaticamente. No bytecode, uma extension function vira uma função estática onde o primeiro parâmetro é o objeto receptor:\n// Isso: fun String.gritando() = this.uppercase() + \u0026#34;!!!\u0026#34; // Vira essencialmente isso no bytecode: // public static String gritando(String $this) { return $this.toUpperCase() + \u0026#34;!!!\u0026#34;; } Isso tem implicações importantes:\nNão há polimorfismo: se uma classe filha e uma classe pai têm extensions com o mesmo nome, o tipo declarado (não o real) determina qual é chamada Membros sempre ganham: se a classe já tem um método com o mesmo nome, o membro da classe vence class Mensagem(val texto: String) { fun exibir() = \u0026#34;Classe: $texto\u0026#34; } fun Mensagem.exibir() = \u0026#34;Extension: $texto\u0026#34; // NUNCA será chamada fun main() { println(Mensagem(\u0026#34;Oi\u0026#34;).exibir()) // \u0026#34;Classe: Oi\u0026#34; — o membro vence } Organizando extensions Em projetos maiores, organize suas extensions em arquivos dedicados:\nsrc/ extensions/ StringExtensions.kt DateExtensions.kt CollectionExtensions.kt ViewExtensions.kt // Android // StringExtensions.kt package br.dev.kotlin.extensions fun String.capitalizar(): String { return this.split(\u0026#34; \u0026#34;).joinToString(\u0026#34; \u0026#34;) { palavra -\u0026gt; palavra.replaceFirstChar { it.uppercase() } } } Boas práticas Use extensions para adicionar funcionalidade coesa a uma classe Não abuse: se a lógica é complexa, talvez uma classe própria faça mais sentido Dê nomes descritivos: a extension deve parecer um membro natural da classe Documente: extensions podem surpreender quem lê o código pela primeira vez Agrupe por tipo: mantenha as extensions organizadas em arquivos temáticos Conclusão Extension Functions são um dos recursos que fazem Kotlin ser tão expressivo e prazeroso de programar. Elas permitem que você adapte a linguagem ao seu domínio, criando uma API fluente e natural. Conceitos similares existem em outras linguagens: Rust tem trait implementations para tipos externos, e Go usa funções com receivers para um efeito parecido. Use com sabedoria, e seu código vai ficar muito mais legível e manutenível.\nBora estender tudo!\n","permalink":"https://kotlin.dev.br/blog/extension-functions-kotlin/","summary":"\u003cp\u003eImagine poder adicionar métodos novos a classes que já existem — sem herança, sem wrappers, sem modificar o código original. Parece mágica? Em Kotlin, isso se chama \u003cstrong\u003eExtension Functions\u003c/strong\u003e, e é um dos recursos mais queridos da linguagem.\u003c/p\u003e\n\u003ch2 id=\"o-que-são-extension-functions\"\u003eO que são Extension Functions?\u003c/h2\u003e\n\u003cp\u003eExtension Functions permitem que você \u0026ldquo;estenda\u0026rdquo; uma classe com novas funções, como se elas fizessem parte da classe original. A sintaxe é simples:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econtarPalavras\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etrim\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s2\"\u003es+\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etoRegex\u003c/span\u003e\u003cspan class=\"p\"\u003e()).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003efrase\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Kotlin é incrível demais da conta\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efrase\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econtarPalavras\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 6\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eRepare: \u003ccode\u003econtarPalavras()\u003c/code\u003e não existe na classe \u003ccode\u003eString\u003c/code\u003e, mas a gente chamou como se existisse. O \u003ccode\u003ethis\u003c/code\u003e dentro da função refere-se ao objeto receptor (no caso, a String).\u003c/p\u003e","title":"Extension Functions em Kotlin — Tutorial em Português | Kotlin Brasil"},{"content":"Sobre a vagaA Amazon busca uma pessoa Engenheira de Desenvolvimento de Software para atuar no time IES LATECH \u0026amp; GIS em Belo Horizonte, Minas Gerais, em modelo presencial.\nRequisitos e tecnologiasExperiência em desenvolvimento de software em nível pleno.Conhecimento em Kotlin, Java, Python, Go, JavaScript, C, C++ ou C#.Experiência com Unix/Linux e Web Services.Local de trabalhoVaga presencial em Belo Horizonte, Minas Gerais, Brasil.\n","permalink":"https://kotlin.dev.br/vagas/ukl3tjpshvxz5fd5-amazon-engenheiro-a-de-desenvolvimento-de-software-ies-latech-g/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Amazon busca uma pessoa Engenheira de Desenvolvimento de Software para atuar no time IES LATECH \u0026amp; GIS em Belo Horizonte, Minas Gerais, em modelo presencial.\u003c/p\u003e\u003ch3\u003eRequisitos e tecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento de software em nível pleno.\u003c/li\u003e\u003cli\u003eConhecimento em Kotlin, Java, Python, Go, JavaScript, C, C++ ou C#.\u003c/li\u003e\u003cli\u003eExperiência com Unix/Linux e Web Services.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em Belo Horizonte, Minas Gerais, Brasil.\u003c/p\u003e","title":"Engenheiro(a) de Desenvolvimento de Software, IES LATECH \u0026 GIS"},{"content":"Se você já programou em Java, com certeza já tomou aquele susto com NullPointerException em produção. Tony Hoare, o criador do conceito de null, chamou isso de \u0026ldquo;o erro de um bilhão de dólares\u0026rdquo;. Kotlin resolveu esse problema de um jeito elegante: o sistema de tipos diferencia referências que podem ser nulas das que não podem. Vamos entender como.\nO problema com null Em linguagens como Java, qualquer referência de objeto pode ser null. Isso significa que toda vez que você acessa um método ou propriedade, existe o risco de um NPE:\n// Em Java, isso compila sem problema, mas estoura em runtime: // String nome = null; // int tamanho = nome.length(); // NullPointerException! Kotlin resolve isso em tempo de compilação. Se o código pode causar NPE, ele simplesmente não compila.\nTipos nullable e non-nullable Em Kotlin, por padrão, variáveis não podem ser nulas:\nvar nome: String = \u0026#34;Karina\u0026#34; // nome = null // ERRO DE COMPILAÇÃO: Null can not be a value of a non-null type String // Para permitir null, adicione ? ao tipo var nomeOpcional: String? = \u0026#34;Karina\u0026#34; nomeOpcional = null // OK, o tipo permite Essa distinção é feita no sistema de tipos: String e String? são tipos diferentes. O compilador sabe exatamente quais variáveis podem ser nulas e te obriga a lidar com isso.\nOperador de chamada segura (?.) O safe call operator é seu melhor amigo quando trabalha com tipos nullable:\nval nome: String? = obterNomeDoUsuario() // Em vez de checar manualmente: // if (nome != null) { println(nome.length) } // Use o operador ?. val tamanho: Int? = nome?.length println(tamanho) // imprime o tamanho ou null // Encadeamento seguro val cidade: String? = usuario?.endereco?.cidade?.uppercase() Se qualquer valor na cadeia for null, a expressão inteira retorna null sem lançar exceção. Lindo, né?\nOperador Elvis (?:) Quando você quer um valor padrão caso algo seja null, use o operador Elvis:\nval nome: String? = null // Valor padrao simples val nomeExibido = nome ?: \u0026#34;Usuário Anônimo\u0026#34; println(nomeExibido) // \u0026#34;Usuário Anônimo\u0026#34; // Combinando com safe call val tamanho = nome?.length ?: 0 println(tamanho) // 0 // Elvis com throw ou return fun buscarUsuario(id: Int): Usuario { val usuario = repositorio.buscar(id) ?: throw UsuarioNaoEncontradoException(id) return usuario } fun processarNome(nome: String?) { val nomeValido = nome ?: return // sai da funcao se for null println(\u0026#34;Processando: $nomeValido\u0026#34;) } O nome \u0026ldquo;Elvis\u0026rdquo; vem do formato ?: que, se você virar de lado, parece o topete do Elvis Presley. Sério!\nOperador de asserção não-nula (!!) O operador !! converte um tipo nullable para non-nullable, lançando NPE se o valor for null:\nval nome: String? = \u0026#34;Karina\u0026#34; val tamanho: Int = nome!!.length // OK, porque nome nao é null val nomeNulo: String? = null // val boom = nomeNulo!!.length // NullPointerException! Atenção: use !! com muita moderação! Cada !! no seu código é um NPE em potencial. Se você está usando !! com frequência, provavelmente tem algo errado no design do código.\nSmart Casts Kotlin é esperto: se você já verificou que algo não é null, ele faz smart cast automaticamente:\nfun imprimir(texto: String?) { if (texto != null) { // Aqui o Kotlin já sabe que texto é String (nao-nullable) println(texto.length) // sem necessidade de ?. ou !! println(texto.uppercase()) } } // Funciona com when tambem fun descrever(valor: Any?) = when (valor) { null -\u0026gt; \u0026#34;Nulo\u0026#34; is String -\u0026gt; \u0026#34;String com ${valor.length} caracteres\u0026#34; // smart cast para String is Int -\u0026gt; \u0026#34;Inteiro: ${valor * 2}\u0026#34; // smart cast para Int else -\u0026gt; \u0026#34;Outro tipo\u0026#34; } let, also e outros scope functions com null A função let é muito usada para executar código somente quando o valor não é null:\nval email: String? = obterEmailDoUsuario() // Executa o bloco apenas se email nao for null email?.let { emailValido -\u0026gt; enviarNotificacao(emailValido) registrarLog(\u0026#34;Email enviado para $emailValido\u0026#34;) } // Versão mais concisa usando it email?.let { enviarNotificacao(it) } Coleções e null safety Kotlin diferencia coleções que contêm elementos nullable daquelas que não contêm:\nval nomes: List\u0026lt;String\u0026gt; = listOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;, \u0026#34;Carla\u0026#34;) val nomesOuNulos: List\u0026lt;String?\u0026gt; = listOf(\u0026#34;Ana\u0026#34;, null, \u0026#34;Carla\u0026#34;) // filterNotNull remove os nulos e muda o tipo val apenasNomes: List\u0026lt;String\u0026gt; = nomesOuNulos.filterNotNull() println(apenasNomes) // [Ana, Carla] // listOfNotNull já filtra na criacao val lista = listOfNotNull(\u0026#34;Ana\u0026#34;, null, \u0026#34;Carla\u0026#34;, null) println(lista) // [Ana, Carla] Interoperabilidade com Java Quando você chama código Java a partir de Kotlin, os tipos vêm como platform types (indicados por !), pois o compilador não sabe se podem ser nulos:\n// Retorno de metodo Java: String! (platform type) val resultado = javaObject.getValor() // Boas praticas: declare o tipo explicitamente val resultadoSeguro: String? = javaObject.getValor() // trata como nullable val resultadoCerto: String = javaObject.getValor() // assume nao-null (pode dar NPE) A recomendação é: quando chamar código Java, trate o retorno como nullable até ter certeza de que não será null.\nBoas práticas Prefira tipos non-nullable sempre que possível Evite !! — quase sempre existe uma alternativa melhor Use ?.let para operações condicionais Use Elvis ?: para valores padrão Valide cedo: converta nullable para non-nullable no início da função Aproveite require e check para válidações: fun processarPedido(pedidoId: String?, valor: Double) { requireNotNull(pedidoId) { \u0026#34;ID do pedido nao pode ser nulo\u0026#34; } require(valor \u0026gt; 0) { \u0026#34;Valor deve ser positivo\u0026#34; } // Aqui pedidoId já é String (non-nullable) println(\u0026#34;Processando pedido $pedidoId no valor de R$ $valor\u0026#34;) } Conclusão Null Safety é provavelmente o recurso que mais vai poupar suas noites de sono como desenvolvedor. O sistema de tipos de Kotlin te força a pensar em cenários nulos durante a codificação, não em produção. Se segurança de tipos te interessa, Rust leva esse conceito ainda mais longe com ownership e borrowing, eliminando toda uma classe de bugs de memória em tempo de compilação. É uma mudança de mentalidade que, depois que você absorve, faz todo o sentido do mundo.\nBora codar sem medo de NPE!\n","permalink":"https://kotlin.dev.br/blog/null-safety-kotlin/","summary":"\u003cp\u003eSe você já programou em Java, com certeza já tomou aquele susto com \u003ccode\u003eNullPointerException\u003c/code\u003e em produção. Tony Hoare, o criador do conceito de null, chamou isso de \u0026ldquo;o erro de um bilhão de dólares\u0026rdquo;. Kotlin resolveu esse problema de um jeito elegante: o sistema de tipos diferencia referências que podem ser nulas das que não podem. Vamos entender como.\u003c/p\u003e\n\u003ch2 id=\"o-problema-com-null\"\u003eO problema com null\u003c/h2\u003e\n\u003cp\u003eEm linguagens como Java, qualquer referência de objeto pode ser \u003ccode\u003enull\u003c/code\u003e. Isso significa que toda vez que você acessa um método ou propriedade, existe o risco de um NPE:\u003c/p\u003e","title":"Null Safety em Kotlin: Como Funciona | Kotlin Brasil"},{"content":"Coroutines são, sem exagero, um dos recursos mais poderosos de Kotlin. Se você já sofreu com callbacks aninhados, threads manuais ou AsyncTask no Android, prepare-se: sua vida vai mudar. Vamos entender como funciona essa mágica.\nO que são Coroutines? Coroutines são uma forma de escrever código assíncrono de maneira sequencial. Em vez de usar callbacks ou encadear Promises, você escreve código que parece síncrono, mas por baixo dos panos executa de forma concorrente e não bloqueante. Cada linguagem moderna tem sua abordagem para concorrência — Go usa goroutines e channels, enquanto Rust aposta em async/await com ownership. Kotlin combina o melhor dos dois mundos.\nPense assim: uma coroutine é como uma função que pode ser pausada e retomada depois, sem bloquear a thread em que está rodando.\nConfiguração Para usar coroutines, adicione a dependência no build.gradle.kts:\ndependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0\u0026#34;) // Para Android: implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0\u0026#34;) } Primeiro exemplo: launch e delay import kotlinx.coroutines.* fun main() = runBlocking { println(\u0026#34;Início - ${Thread.currentThread().name}\u0026#34;) launch { delay(1000) // pausa sem bloquear a thread println(\u0026#34;Coroutine 1 finalizou!\u0026#34;) } launch { delay(500) println(\u0026#34;Coroutine 2 finalizou!\u0026#34;) } println(\u0026#34;Coroutines disparadas!\u0026#34;) } Saída:\nInício - main Coroutines disparadas! Coroutine 2 finalizou! Coroutine 1 finalizou! Repare: as duas coroutines rodaram concorrentemente, e a coroutine 2 terminou primeiro porque tinha menos delay. Tudo isso sem criar threads extras.\nSuspend Functions O coração das coroutines são as suspend functions — funções que podem ser suspensas e retomadas:\nsuspend fun buscarDadosDoServidor(): String { delay(2000) // simula uma chamada de rede return \u0026#34;Dados recebidos com sucesso!\u0026#34; } suspend fun buscarDoBancoDeDados(): String { delay(1000) // simula consulta ao banco return \u0026#34;Dados do banco carregados!\u0026#34; } fun main() = runBlocking { val inicio = System.currentTimeMillis() // Execução sequencial val servidor = buscarDadosDoServidor() val banco = buscarDoBancoDeDados() println(\u0026#34;$servidor | $banco\u0026#34;) println(\u0026#34;Tempo sequencial: ${System.currentTimeMillis() - inicio}ms\u0026#34;) // ~3000ms } async e await: execução paralela Quando as chamadas são independentes, use async para rodá-las em paralelo:\nfun main() = runBlocking { val inicio = System.currentTimeMillis() // Execução paralela com async val servidorDeferred = async { buscarDadosDoServidor() } val bancoDeferred = async { buscarDoBancoDeDados() } val servidor = servidorDeferred.await() val banco = bancoDeferred.await() println(\u0026#34;$servidor | $banco\u0026#34;) println(\u0026#34;Tempo paralelo: ${System.currentTimeMillis() - inicio}ms\u0026#34;) // ~2000ms } A diferença é gritante: de 3 segundos caiu pra 2. O async dispara as duas operações ao mesmo tempo, e o await() espera o resultado.\nDispatchers: controlando onde a coroutine roda Dispatchers determinam em qual thread (ou pool de threads) a coroutine será executada:\nfun main() = runBlocking { // Thread principal launch(Dispatchers.Main) { // Atualizar UI (Android) } // Pool de threads otimizado para I/O launch(Dispatchers.IO) { // Chamadas de rede, leitura de arquivo, banco de dados val dados = fazerChamadaDeRede() } // Pool otimizado para CPU launch(Dispatchers.Default) { // Cálculos pesados, processamento de imagem val resultado = processarDadosPesados() } } No dia a dia:\nDispatchers.Main: atualizar interface (Android/Desktop) Dispatchers.IO: operações de entrada/saída Dispatchers.Default: trabalho intensivo de CPU withContext: trocar de dispatcher Muitas vezes você precisa trocar de contexto dentro da mesma coroutine:\nclass UsuarioRepository(private val api: ApiService) { suspend fun buscarUsuario(id: Int): Usuario { // Faz a chamada de rede em IO return withContext(Dispatchers.IO) { api.getUsuario(id) } } } // No ViewModel (Android): class UsuarioViewModel : ViewModel() { fun carregar() { viewModelScope.launch { // roda em Main por padrao val usuario = repository.buscarUsuario(42) // muda pra IO internamente _uiState.value = UiState.Sucesso(usuario) // volta pra Main } } } Tratamento de erros Coroutines oferecem tratamento de erros com try/catch convencional:\nsuspend fun operacaoArriscada(): String { delay(500) throw IllegalStateException(\u0026#34;Deu ruim!\u0026#34;) } fun main() = runBlocking { // Opção 1: try/catch simples try { val resultado = operacaoArriscada() println(resultado) } catch (e: Exception) { println(\u0026#34;Erro capturado: ${e.message}\u0026#34;) } // Opção 2: CoroutineExceptionHandler val handler = CoroutineExceptionHandler { _, exception -\u0026gt; println(\u0026#34;Handler capturou: ${exception.message}\u0026#34;) } val job = CoroutineScope(Dispatchers.Default + handler).launch { operacaoArriscada() } job.join() } Cancelamento de coroutines Uma das belezas das coroutines é o cancelamento cooperativo:\nfun main() = runBlocking { val job = launch { repeat(1000) { i -\u0026gt; println(\u0026#34;Processando item $i...\u0026#34;) delay(100) // ponto de cancelamento } } delay(500) println(\u0026#34;Cansamos, vamos cancelar!\u0026#34;) job.cancelAndJoin() println(\u0026#34;Job cancelado com sucesso!\u0026#34;) } Todas as suspend functions da biblioteca padrão (delay, yield, etc.) verificam o cancelamento automaticamente. Se você tem loops sem suspend functions, use isActive ou ensureActive().\nExemplo prático: buscar dados de várias APIs Vamos a um cenário real — buscar dados de múltiplas fontes e combinar:\ndata class PaginaInicial( val noticias: List\u0026lt;Noticia\u0026gt;, val clima: Clima, val cotacaoDolar: Double ) suspend fun carregarPaginaInicial(): PaginaInicial = coroutineScope { val noticias = async { noticiaService.buscarUltimas() } val clima = async { climaService.buscarPrevisao(\u0026#34;São Paulo\u0026#34;) } val cotacao = async { financeiroService.buscarCotacaoDolar() } PaginaInicial( noticias = noticias.await(), clima = clima.await(), cotacaoDolar = cotacao.await() ) } As três chamadas rodam em paralelo e o resultado é combinado. Limpo, eficiente e fácil de entender.\nConclusão Coroutines são o jeito Kotlin de lidar com concorrência: simples, seguro e poderoso. Se você tem curiosidade sobre como outras linguagens resolvem concorrência, Go usa goroutines com uma abordagem similar de leveza, Rust implementa async/await com zero-cost abstractions, e Python usa async/await — veja async em Python. Uma vez que você pega o jeito, não vai querer voltar pra callbacks nunca mais. O segredo é praticar — comece substituindo chamadas assíncronas no seu projeto por coroutines e veja a diferença na legibilidade do código.\nNo próximo post, vamos falar sobre Kotlin Flow — o sistema reativo que se integra perfeitamente com coroutines. Até lá!\n","permalink":"https://kotlin.dev.br/blog/coroutines-kotlin/","summary":"\u003cp\u003eCoroutines são, sem exagero, um dos recursos mais poderosos de Kotlin. Se você já sofreu com callbacks aninhados, threads manuais ou AsyncTask no Android, prepare-se: sua vida vai mudar. Vamos entender como funciona essa mágica.\u003c/p\u003e\n\u003ch2 id=\"o-que-são-coroutines\"\u003eO que são Coroutines?\u003c/h2\u003e\n\u003cp\u003eCoroutines são uma forma de escrever código assíncrono de maneira sequencial. Em vez de usar callbacks ou encadear Promises, você escreve código que parece síncrono, mas por baixo dos panos executa de forma concorrente e não bloqueante. Cada linguagem moderna tem sua abordagem para concorrência — \u003ca href=\"https://golang.com.br/\" target=\"_blank\" rel=\"noopener\" onclick=\"umami.track('portfolio-site-click', { destination: 'golang.com.br' })\"\u003eGo usa goroutines e channels\u003c/a\u003e, enquanto \u003ca href=\"https://rustlang.com.br/\" target=\"_blank\" rel=\"noopener\" onclick=\"umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })\"\u003eRust aposta em async/await com ownership\u003c/a\u003e. Kotlin combina o melhor dos dois mundos.\u003c/p\u003e","title":"Coroutines em Kotlin: Guia Completo em Português | Kotlin Brasil"},{"content":"Sobre a vagaO Inter busca Desenvolvedor Mobile iOS/Android para atuação presencial em São Paulo, com oportunidades para níveis pleno, sênior e especialista.\nTecnologiasKotlin, Jetpack, Coroutines e Gradle para Android.Swift, SwiftUI e Xcode para iOS.Arquitetura MVVM.Testes unitários e testes de UI.RequisitosExperiência em desenvolvimento mobile iOS e/ou Android.Conhecimento nas tecnologias informadas para construção, manutenção e testes de aplicativos móveis.Disponibilidade para trabalho presencial em São Paulo. ","permalink":"https://kotlin.dev.br/vagas/hr751yzdhy2qv9i8-inter-desenvolvedor-mobile-ios-android-pleno-senior-e-especiali/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eO Inter busca Desenvolvedor Mobile iOS/Android para atuação presencial em São Paulo, com oportunidades para níveis pleno, sênior e especialista.\u003c/p\u003e\u003ch3\u003eTecnologias\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Jetpack, Coroutines e Gradle para Android.\u003c/li\u003e\u003cli\u003eSwift, SwiftUI e Xcode para iOS.\u003c/li\u003e\u003cli\u003eArquitetura MVVM.\u003c/li\u003e\u003cli\u003eTestes unitários e testes de UI.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento mobile iOS e/ou Android.\u003c/li\u003e\u003cli\u003eConhecimento nas tecnologias informadas para construção, manutenção e testes de aplicativos móveis.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho presencial em São Paulo.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Mobile iOS/Android Pleno, Sênior e Especialista"},{"content":"Sobre a vagaProcuramos desenvolvedores mobile sênior e especialistas para integrar nosso time em Recife. Você trabalhará com tecnologias modernas em plataformas iOS e Android, desenvolvendo soluções de alta qualidade para aplicações financeiras.\nResponsabilidadesDesenvolver e manter aplicações mobile para iOS e AndroidImplementar arquitetura MVVM em projetos mobileEscrever e manter testes unitários e de UIColaborar com times de design e backendRevisar código e contribuir para melhorias contínuasRequisitosExperiência sênior em desenvolvimento mobile (iOS e/ou Android)Conhecimento em Swift e SwiftUI (iOS) ou Kotlin e Jetpack (Android)Experiência com padrão MVVMConhecimento em testes unitários e UI testingExcelente comunicação e trabalho em equipeDiferenciaisExperiência com ambas as plataformas (iOS e Android)Conhecimento em desenvolvimento financeiro ou fintechContribuições open source ","permalink":"https://kotlin.dev.br/vagas/ce07k9gig7y997qt-inter-co-developer-mobile-ios-android-pl-sr-spec/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eProcuramos desenvolvedores mobile sênior e especialistas para integrar nosso time em Recife. Você trabalhará com tecnologias modernas em plataformas iOS e Android, desenvolvendo soluções de alta qualidade para aplicações financeiras.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações mobile para iOS e Android\u003c/li\u003e\u003cli\u003eImplementar arquitetura MVVM em projetos mobile\u003c/li\u003e\u003cli\u003eEscrever e manter testes unitários e de UI\u003c/li\u003e\u003cli\u003eColaborar com times de design e backend\u003c/li\u003e\u003cli\u003eRevisar código e contribuir para melhorias contínuas\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento mobile (iOS e/ou Android)\u003c/li\u003e\u003cli\u003eConhecimento em Swift e SwiftUI (iOS) ou Kotlin e Jetpack (Android)\u003c/li\u003e\u003cli\u003eExperiência com padrão MVVM\u003c/li\u003e\u003cli\u003eConhecimento em testes unitários e UI testing\u003c/li\u003e\u003cli\u003eExcelente comunicação e trabalho em equipe\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com ambas as plataformas (iOS e Android)\u003c/li\u003e\u003cli\u003eConhecimento em desenvolvimento financeiro ou fintech\u003c/li\u003e\u003cli\u003eContribuições open source\u003c/li\u003e\u003c/ul\u003e","title":"Developer Mobile iOS/Android (Pl, Sr \u0026 Spec)"},{"content":"Sobre a vagaA Inter\u0026Co procura um Developer Mobile Senior experiente em iOS e Android para contribuir no desenvolvimento de aplicações mobile de alta qualidade e performance.\nResponsabilidadesDesenvolver e manter aplicações iOS e AndroidColaborar com times de design e backendImplementar arquitetura clean e padrões de qualidadeParticipar de code reviews e mentoria técnicaRequisitosExperiência sênior com Kotlin e SwiftDomínio de SwiftUI e JetpackConhecimento de MVVM e arquitetura mobileExperiência com testes automatizados (XCTest, JUnit)Familiaridade com CI/CD (Fastlane, Xcode Cloud, Gradle)DiferenciaisExperiência com múltiplas plataformas mobileConhecimento em performance e otimizaçãoContribuição em projetos open source ","permalink":"https://kotlin.dev.br/vagas/dxg1bdpjrid8ehc2-inter-co-developer-mobile-ios-android-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Inter\u0026Co procura um Developer Mobile Senior experiente em iOS e Android para contribuir no desenvolvimento de aplicações mobile de alta qualidade e performance.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter aplicações iOS e Android\u003c/li\u003e\u003cli\u003eColaborar com times de design e backend\u003c/li\u003e\u003cli\u003eImplementar arquitetura clean e padrões de qualidade\u003c/li\u003e\u003cli\u003eParticipar de code reviews e mentoria técnica\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior com Kotlin e Swift\u003c/li\u003e\u003cli\u003eDomínio de SwiftUI e Jetpack\u003c/li\u003e\u003cli\u003eConhecimento de MVVM e arquitetura mobile\u003c/li\u003e\u003cli\u003eExperiência com testes automatizados (XCTest, JUnit)\u003c/li\u003e\u003cli\u003eFamiliaridade com CI/CD (Fastlane, Xcode Cloud, Gradle)\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eDiferenciais\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência com múltiplas plataformas mobile\u003c/li\u003e\u003cli\u003eConhecimento em performance e otimização\u003c/li\u003e\u003cli\u003eContribuição em projetos open source\u003c/li\u003e\u003c/ul\u003e","title":"Developer Mobile iOS/Android Senior"},{"content":"Sobre a vagaVaga sênior para Engenheiro(a) de Software no Banco PAN, em modelo híbrido em São Paulo, São Paulo.\nStack e contexto técnicoLinguagens: Kotlin e Java.Cloud e infraestrutura: AWS, Docker, Kubernetes, S3, Lambda e Step Functions.Mensageria: Kafka e SQS/SNS.Banco de dados: SQL e MySQL.APIs: desenvolvimento e integração com APIs REST.Qualidade: práticas de TDD.Observabilidade: Dynatrace, Grafana e Elastic.RequisitosExperiência sênior em engenharia de software.Vivência com desenvolvimento backend usando Kotlin e Java.Experiência com ambientes em AWS e aplicações conteinerizadas.Conhecimento em microsserviços, APIs REST, mensageria e bancos relacionais.Modelo de trabalhoModelo híbrido, com atuação em São Paulo, São Paulo.\n","permalink":"https://kotlin.dev.br/vagas/kto3bqjj6urnyft7-banco-pan-engenheiro-a-de-software-senior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eVaga sênior para Engenheiro(a) de Software no Banco PAN, em modelo híbrido em São Paulo, São Paulo.\u003c/p\u003e\u003ch3\u003eStack e contexto técnico\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eLinguagens:\u003c/strong\u003e Kotlin e Java.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eCloud e infraestrutura:\u003c/strong\u003e AWS, Docker, Kubernetes, S3, Lambda e Step Functions.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eMensageria:\u003c/strong\u003e Kafka e SQS/SNS.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eBanco de dados:\u003c/strong\u003e SQL e MySQL.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eAPIs:\u003c/strong\u003e desenvolvimento e integração com APIs REST.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eQualidade:\u003c/strong\u003e práticas de TDD.\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eObservabilidade:\u003c/strong\u003e Dynatrace, Grafana e Elastic.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em engenharia de software.\u003c/li\u003e\u003cli\u003eVivência com desenvolvimento backend usando Kotlin e Java.\u003c/li\u003e\u003cli\u003eExperiência com ambientes em AWS e aplicações conteinerizadas.\u003c/li\u003e\u003cli\u003eConhecimento em microsserviços, APIs REST, mensageria e bancos relacionais.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eModelo de trabalho\u003c/h3\u003e\u003cp\u003eModelo híbrido, com atuação em São Paulo, São Paulo.\u003c/p\u003e","title":"Engenheiro(a) de Software Sênior"},{"content":"Se você quer desenvolver apps Android em 2026, Kotlin é o caminho. Desde 2019, o Google recomenda Kotlin como linguagem principal para Android, e hoje praticamente toda a documentação oficial e novos recursos são pensados primeiro em Kotlin. Vamos ver como começar.\nPor que Kotlin para Android? Não é exagero dizer que Kotlin revolucionou o desenvolvimento Android. Antes, a gente escrevia toneladas de boilerplate em Java, lidava com NullPointerException a todo momento e sofria com callbacks aninhados. Kotlin resolveu tudo isso de uma vez.\nOs principais benefícios para Android:\nJetpack Compose: o toolkit moderno de UI do Android é escrito em Kotlin Coroutines: substituem AsyncTask e callbacks complexos Null Safety: menos crashes em produção Código conciso: menos linhas, menos bugs, mais clareza Interop com Java: seu código legado continua funcionando Para fluxos que usam hardware, também vale estudar CameraX com Jetpack Compose e Kotlin, porque câmera combina permissão, lifecycle, performance e estado de UI no mesmo recurso.\nConfigurando o ambiente Para começar, você precisa do Android Studio (que já vem com suporte nativo a Kotlin). Ao criar um novo projeto, selecione Kotlin como linguagem — simples assim.\nNo build.gradle.kts do seu módulo app, as dependências básicas ficam assim:\nplugins { id(\u0026#34;com.android.application\u0026#34;) id(\u0026#34;org.jetbrains.kotlin.android\u0026#34;) id(\u0026#34;org.jetbrains.kotlin.plugin.compose\u0026#34;) } android { namespace = \u0026#34;br.dev.kotlin.meuapp\u0026#34; compileSdk = 35 defaultConfig { applicationId = \u0026#34;br.dev.kotlin.meuapp\u0026#34; minSdk = 24 targetSdk = 35 } } dependencies { implementation(platform(\u0026#34;androidx.compose:compose-bom:2025.12.01\u0026#34;)) implementation(\u0026#34;androidx.compose.ui:ui\u0026#34;) implementation(\u0026#34;androidx.compose.material3:material3\u0026#34;) implementation(\u0026#34;androidx.activity:activity-compose:1.9.0\u0026#34;) implementation(\u0026#34;androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0\u0026#34;) } Jetpack Compose: UI moderna com Kotlin Jetpack Compose mudou completamente a forma de construir interfaces no Android. Esqueça XML — agora tudo é código Kotlin declarativo.\n@Composable fun TelaDeBoasVindas(nome: String) { Column( modifier = Modifier .fillMaxSize() .padding(24.dp), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Text( text = \u0026#34;Fala, $nome!\u0026#34;, style = MaterialTheme.typography.headlineLarge ) Spacer(modifier = Modifier.height(16.dp)) Text( text = \u0026#34;Bem-vindo ao app Kotlin Brasil\u0026#34;, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurfaceVariant ) Spacer(modifier = Modifier.height(32.dp)) Button(onClick = { /* ação aqui */ }) { Text(\u0026#34;Começar\u0026#34;) } } } Repare como é intuitivo: você compõe a tela usando funções. Cada @Composable é um bloco de construção reutilizável.\nGerenciamento de estado No Compose, estado é tudo. Quando o estado muda, a UI recompõe automaticamente:\n@Composable fun ContadorSimples() { var contagem by remember { mutableIntStateOf(0) } Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(16.dp) ) { Text( text = \u0026#34;Contagem: $contagem\u0026#34;, style = MaterialTheme.typography.displayMedium ) Spacer(modifier = Modifier.height(16.dp)) Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { Button(onClick = { contagem-- }) { Text(\u0026#34;-\u0026#34;) } Button(onClick = { contagem++ }) { Text(\u0026#34;+\u0026#34;) } } } } ViewModel com Kotlin Para estado mais complexo, usamos ViewModel com StateFlow:\ndata class ListaDeTarefasUiState( val tarefas: List\u0026lt;String\u0026gt; = emptyList(), val carregando: Boolean = false ) class TarefasViewModel : ViewModel() { private val _uiState = MutableStateFlow(ListaDeTarefasUiState()) val uiState: StateFlow\u0026lt;ListaDeTarefasUiState\u0026gt; = _uiState.asStateFlow() fun adicionarTarefa(tarefa: String) { _uiState.update { estadoAtual -\u0026gt; estadoAtual.copy( tarefas = estadoAtual.tarefas + tarefa ) } } fun carregarTarefas() { viewModelScope.launch { _uiState.update { it.copy(carregando = true) } val tarefas = repositorio.buscarTarefas() // suspend function _uiState.update { it.copy(tarefas = tarefas, carregando = false) } } } } @Composable fun TelaDeTarefas(viewModel: TarefasViewModel = viewModel()) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() if (uiState.carregando) { CircularProgressIndicator() } else { LazyColumn { items(uiState.tarefas) { tarefa -\u0026gt; Text(text = tarefa, modifier = Modifier.padding(16.dp)) } } } } Navegação com Compose A navegação entre telas em Compose ficou bem mais simples:\n@Composable fun AppNavigation() { val navController = rememberNavController() NavHost(navController = navController, startDestination = \u0026#34;home\u0026#34;) { composable(\u0026#34;home\u0026#34;) { TelaInicial( onNavigateToDetalhes = { id -\u0026gt; navController.navigate(\u0026#34;detalhes/$id\u0026#34;) } ) } composable(\u0026#34;detalhes/{id}\u0026#34;) { backStackEntry -\u0026gt; val id = backStackEntry.arguments?.getString(\u0026#34;id\u0026#34;) TelaDetalhes(id = id) } } } Quando essa navegação precisa ser aberta por notificações, e-mails ou páginas web, trate o contrato de URL como parte da arquitetura. O guia de App Links e deep links no Android com Kotlin mostra como validar rotas externas, integrar com Navigation Compose e testar links críticos.\nChamadas de rede com Coroutines Aqui é onde Kotlin brilha no Android. Nada de callbacks ou AsyncTask:\nclass UsuarioRepository(private val api: ApiService) { suspend fun buscarUsuarios(): Result\u0026lt;List\u0026lt;Usuario\u0026gt;\u0026gt; { return try { val response = api.getUsuarios() Result.success(response) } catch (e: Exception) { Result.failure(e) } } } A palavra-chave suspend indica que essa função pode ser pausada sem bloquear a thread. Combinada com viewModelScope.launch, ela roda fora da main thread automaticamente.\nBoas práticas para Android com Kotlin Use StateFlow em vez de LiveData em projetos novos — é mais idiomático em Kotlin e se integra melhor com coroutines Prefira val sobre var — imutabilidade previne bugs e facilita o raciocínio sobre o código Aplique a arquitetura recomendada: UI Layer \u0026gt; Domain Layer \u0026gt; Data Layer. Separar responsabilidades facilita a manutenção e os testes Escreva testes de Compose com createComposeRule() — testes de UI garantem que mudanças não quebrem a experiência do usuário Use Hilt ou Koin para injeção de dependências — evite instanciar dependências manualmente nos Composables e ViewModels Evite lógica de negócio em Composables — delegue pro ViewModel para manter as funções @Composable focadas apenas na renderização da UI Modularize seu projeto — conforme o app cresce, separar features em módulos Gradle melhora o tempo de build e a organização do código. Para uma estratégia completa, veja modularização Android com Kotlin e Compose Use collectAsStateWithLifecycle() em vez de collectAsState() — ele respeita o ciclo de vida e para de coletar quando o app vai para background, economizando recursos Testes de UI com Compose Testar telas em Compose é simples e intuitivo. Usando createComposeRule(), você consegue verificar se os elementos estão visíveis e se as interações funcionam corretamente:\n@get:Rule val composeTestRule = createComposeRule() @Test fun telaDeBoasVindas_exibeNomeDoUsuario() { composeTestRule.setContent { TelaDeBoasVindas(nome = \u0026#34;Karina\u0026#34;) } composeTestRule .onNodeWithText(\u0026#34;Fala, Karina!\u0026#34;) .assertIsDisplayed() composeTestRule .onNodeWithText(\u0026#34;Começar\u0026#34;) .assertIsDisplayed() .performClick() } Você pode buscar elementos por texto, por testTag ou por semântica. O importante é cobrir os fluxos principais do app para garantir que regressões sejam detectadas rapidamente.\nConclusão Kotlin e Android formam uma dupla imbatível em 2026. Com Jetpack Compose, coroutines e todo o ecossistema do Jetpack, desenvolver apps nunca foi tão produtivo e prazeroso. Para o backend do seu app, considere usar Kotlin com Spring Boot/Ktor, ou explore Go e Python como alternativas. Se você está entrando no mundo mobile, comece direto com Kotlin — não tem por que passar pelo Java primeiro.\nNo próximo post, vamos mergulhar nas coroutines e entender como funcionam por debaixo dos panos. Até lá!\n","permalink":"https://kotlin.dev.br/blog/kotlin-para-android/","summary":"\u003cp\u003eSe você quer desenvolver apps Android em 2026, Kotlin é o caminho. Desde 2019, o Google recomenda Kotlin como linguagem principal para Android, e hoje praticamente toda a documentação oficial e novos recursos são pensados primeiro em Kotlin. Vamos ver como começar.\u003c/p\u003e\n\u003ch2 id=\"por-que-kotlin-para-android\"\u003ePor que Kotlin para Android?\u003c/h2\u003e\n\u003cp\u003eNão é exagero dizer que Kotlin revolucionou o desenvolvimento Android. Antes, a gente escrevia toneladas de boilerplate em Java, lidava com NullPointerException a todo momento e sofria com callbacks aninhados. Kotlin resolveu tudo isso de uma vez.\u003c/p\u003e","title":"Kotlin para Android: Guia Completo em Português | Kotlin Brasil"},{"content":"\u0026ldquo;Devo aprender Kotlin ou Java?\u0026rdquo; — essa é de longe a pergunta que mais recebemos aqui no Kotlin Brasil. A verdade é que não existe resposta única, mas vou te dar todos os argumentos pra você decidir com segurança.\nKotlin e Java: uma convivência pacífica Antes de tudo, vale lembrar: Kotlin não veio pra matar o Java. As duas linguagens rodam na JVM e são 100% interoperáveis. Você pode chamar código Java de Kotlin e vice-versa, misturar arquivos no mesmo projeto sem problema nenhum.\nDito isso, Kotlin foi criada justamente para ser uma evolução. Vamos ver na prática onde cada uma se destaca.\nComparação de sintaxe Declaração de classe com dados Java:\n// Em Java, voce precisaria de tudo isso: // public class Usuario { // private String nome; // private String email; // // construtor, getters, setters, equals, hashCode, toString... // // facilmente 50+ linhas // } Kotlin:\ndata class Usuario(val nome: String, val email: String) // Pronto. Uma linha. Com equals, hashCode, toString e copy inclusos. Null Safety Java:\n// Em Java, qualquer referência pode ser null // String nome = null; // nome.length(); // BOOM! NullPointerException em runtime Kotlin:\nvar nome: String = \u0026#34;Karina\u0026#34; // nome = null // Erro de compilacao! Não compila. var nomeOpcional: String? = \u0026#34;Karina\u0026#34; nomeOpcional = null // Tudo certo, o tipo permite // Acesso seguro val tamanho = nomeOpcional?.length // retorna null em vez de estourar val tamanhoOuZero = nomeOpcional?.length ?: 0 // Elvis operator Expressões when vs switch Java (switch tradicional):\n// switch limitado a tipos primitivos e strings (até Java 17) Kotlin:\nfun formatarDocumento(doc: Any): String = when (doc) { is CPF -\u0026gt; \u0026#34;CPF: ${doc.numero}\u0026#34; is CNPJ -\u0026gt; \u0026#34;CNPJ: ${doc.numero}\u0026#34; is RG -\u0026gt; \u0026#34;RG: ${doc.numero}\u0026#34; else -\u0026gt; \u0026#34;Documento nao reconhecido\u0026#34; } O when do Kotlin aceita qualquer tipo, faz smart cast automaticamente e pode ser usado como expressão (retorna valor).\nCoroutines vs Threads Essa é uma das maiores vantagens do Kotlin. Enquanto Java depende de threads tradicionais (ou o Project Loom com virtual threads), Kotlin tem coroutines nativamente:\nimport kotlinx.coroutines.* suspend fun buscarUsuario(id: Int): Usuario { delay(1000) // simula chamada de rede return Usuario(\u0026#34;Dev #$id\u0026#34;, \u0026#34;dev$id@email.com\u0026#34;) } fun main() = runBlocking { val usuarios = (1..100).map { id -\u0026gt; async { buscarUsuario(id) } }.awaitAll() println(\u0026#34;Carregados ${usuarios.size} usuários\u0026#34;) } Esse código dispara 100 requisições concorrentes de forma leve, sem criar 100 threads. É elegante e performático.\nExtension Functions Em Kotlin, você pode adicionar funções a classes existentes sem herança:\nfun String.toCpfFormatado(): String { require(this.length == 11) { \u0026#34;CPF deve ter 11 dígitos\u0026#34; } return \u0026#34;${substring(0,3)}.${substring(3,6)}.${substring(6,9)}-${substring(9)}\u0026#34; } val cpf = \u0026#34;12345678901\u0026#34; println(cpf.toCpfFormatado()) // 123.456.789-01 Em Java, você precisaria de uma classe utilitária (StringUtils.formatarCpf(cpf)). Em Kotlin, o código fica muito mais natural e legível.\nOnde Java ainda se destaca Seria injusto não reconhecer os pontos fortes do Java:\nEcossistema maduro: mais de 25 anos de bibliotecas, frameworks e ferramentas Comunidade gigante: mais fácil achar ajuda e profissionais Performance estável: a JVM foi otimizada durante décadas para Java Mercado de trabalho consolidado: ainda há mais vagas Java do que Kotlin no Brasil (embora a diferença esteja diminuindo) Evolução recente: Java 21+ trouxe records, sealed classes, pattern matching e virtual threads Onde Kotlin leva vantagem Sintaxe concisa: até 40% menos código que Java para a mesma funcionalidade Null Safety nativo: menos bugs em produção Coroutines: programação assíncrona de primeiro nível Extension Functions: código mais expressivo Data Classes: adeus boilerplate Android: linguagem preferencial do Google Multiplatform: compartilhar código entre plataformas Benchmark de produtividade Um estudo interno do Google mostrou que equipes usando Kotlin para Android tiveram:\nMenos crashes: redução de NullPointerException em até 33% Menos código: projetos com 25-40% menos linhas Mais satisfação: desenvolvedores reportaram maior produtividade e prazer ao codar Migração de Java para Kotlin Se você já tem um projeto Java, a boa notícia é que a migração pode ser gradual:\nComece pelos testes: converta seus testes primeiro Novos arquivos em Kotlin: toda feature nova, escreva em Kotlin Conversão automática: o IntelliJ converte Java para Kotlin automaticamente (menu: Code \u0026gt; Convert Java File to Kotlin File) Refatore aos poucos: vá melhorando o código convertido com recursos idiomáticos do Kotlin Qual escolher em 2026? A minha recomendação sincera:\nProjeto novo Android? Kotlin, sem pensar duas vezes Backend novo? Kotlin com Spring Boot ou Ktor é uma excelente escolha Projeto legado Java? Migre gradualmente, comece pelo que faz sentido Primeiro emprego? Aprenda ambas — Java pra entender a base, Kotlin pra ser produtivo Multiplataforma? Kotlin Multiplatform é a aposta mais promissora do momento Conclusão Kotlin e Java não são inimigas — são parceiras de ecossistema. Mas se você quer escrever código mais limpo, seguro e moderno em 2026, Kotlin é o caminho. Se o seu interesse vai além da JVM, vale conferir também linguagens como Go para backend e Python para data science e automação. A curva de aprendizado é suave (especialmente pra quem já conhece Java) e o retorno em produtividade é quase imediato.\nSe você está comparando linguagens para backend, vale dar uma olhada também em Go, que é forte em microsserviços e cloud, e Rust, para quem prioriza performance e segurança de memória.\nE aí, já fez sua escolha? Conta pra gente nos comentários!\n","permalink":"https://kotlin.dev.br/blog/kotlin-vs-java/","summary":"\u003cp\u003e\u0026ldquo;Devo aprender Kotlin ou Java?\u0026rdquo; — essa é de longe a pergunta que mais recebemos aqui no Kotlin Brasil. A verdade é que não existe resposta única, mas vou te dar todos os argumentos pra você decidir com segurança.\u003c/p\u003e\n\u003ch2 id=\"kotlin-e-java-uma-convivência-pacífica\"\u003eKotlin e Java: uma convivência pacífica\u003c/h2\u003e\n\u003cp\u003eAntes de tudo, vale lembrar: Kotlin não veio pra matar o Java. As duas linguagens rodam na JVM e são 100% interoperáveis. Você pode chamar código Java de Kotlin e vice-versa, misturar arquivos no mesmo projeto sem problema nenhum.\u003c/p\u003e","title":"Kotlin vs Java: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Se você está começando no mundo da programação ou já manja de Java e quer conhecer algo mais moderno, este guia é pra você. Vamos explorar tudo sobre Kotlin — do zero ao primeiro código rodando.\nO que é Kotlin? Kotlin é uma linguagem de programação criada pela JetBrains (a mesma empresa por trás do IntelliJ IDEA) e lançada oficialmente em 2016. Desde 2019, o Google a considera a linguagem preferencial para desenvolvimento Android, e desde então ela só cresceu.\nKotlin roda na JVM (Java Virtual Machine), o que significa que ela é 100% interoperável com Java. Mas não para por aí: Kotlin também compila para JavaScript e código nativo, graças ao Kotlin Multiplatform.\nPor que Kotlin está tão popular? A resposta é simples: produtividade. Kotlin foi projetada para resolver as dores de cabeça que os desenvolvedores Java enfrentam há anos. Código verboso, NullPointerException, boilerplate excessivo — tudo isso fica no passado com Kotlin.\nAlguns pontos que fazem Kotlin brilhar:\nSintaxe concisa: você escreve menos código pra fazer a mesma coisa Null Safety: o compilador te protege de erros com nulo Interoperabilidade com Java: dá pra usar qualquer biblioteca Java Coroutines: programação assíncrona sem dor de cabeça Multiplataforma: um só código pra Android, iOS, web e backend Seu primeiro programa em Kotlin Vamos ao que interessa: código! O clássico \u0026ldquo;Hello, World!\u0026rdquo; em Kotlin é assim:\nfun main() { println(\u0026#34;Olá, mundo! Bem-vindo ao Kotlin Brasil!\u0026#34;) } Repara que não precisa de classe, não precisa de public static void main(String[] args). Direto ao ponto.\nVariáveis em Kotlin Kotlin tem dois tipos de variáveis: val (imutável) e var (mutável).\nval nome = \u0026#34;Karina\u0026#34; // nao pode ser reatribuída var idade = 28 // pode mudar de valor idade = 29 // tudo certo! // O tipo é inferido, mas voce pode declarar explicitamente val linguagem: String = \u0026#34;Kotlin\u0026#34; val versao: Double = 2.1 A dica de ouro é: prefira val sempre que possível. Imutabilidade torna seu código mais previsível e seguro.\nFunções em Kotlin Declarar funções em Kotlin é bem direto:\nfun saudacao(nome: String): String { return \u0026#34;E aí, $nome! Beleza?\u0026#34; } // Função de expressão unica (single-expression function) fun dobro(x: Int) = x * 2 // Parâmetros com valor padrao fun apresentar(nome: String, linguagem: String = \u0026#34;Kotlin\u0026#34;) { println(\u0026#34;Meu nome é $nome e eu programo em $linguagem\u0026#34;) } fun main() { println(saudacao(\u0026#34;Dev\u0026#34;)) // E aí, Dev! Beleza? println(dobro(21)) // 42 apresentar(\u0026#34;Karina\u0026#34;) // Meu nome é Karina e eu programo em Kotlin apresentar(\u0026#34;João\u0026#34;, \u0026#34;Java\u0026#34;) // Meu nome é João e eu programo em Java } Percebeu o $nome dentro da string? Isso é string template, e é uma mão na roda!\nClasses e Data Classes Em Kotlin, criar classes é muito mais enxuto do que em Java:\n// Classe simples class Pessoa(val nome: String, var idade: Int) // Data class — já vem com equals(), hashCode(), toString() e copy() data class Desenvolvedor( val nome: String, val linguagem: String, val experienciaAnos: Int ) fun main() { val dev = Desenvolvedor(\u0026#34;Karina\u0026#34;, \u0026#34;Kotlin\u0026#34;, 5) println(dev) // Desenvolvedor(nome=Karina, linguagem=Kotlin, experienciaAnos=5) val devSenior = dev.copy(experienciaAnos = 10) println(devSenior) // Desenvolvedor(nome=Karina, linguagem=Kotlin, experienciaAnos=10) } A data class é um dos recursos mais amados por quem usa Kotlin. Aquele tanto de boilerplate que você escrevia em Java (getters, setters, equals, hashCode) simplesmente desaparece.\nControle de fluxo com when O when do Kotlin é o switch do Java, só que muito mais poderoso:\nfun classificarNota(nota: Int): String = when { nota \u0026gt;= 9 -\u0026gt; \u0026#34;Excelente\u0026#34; nota \u0026gt;= 7 -\u0026gt; \u0026#34;Bom\u0026#34; nota \u0026gt;= 5 -\u0026gt; \u0026#34;Regular\u0026#34; else -\u0026gt; \u0026#34;Precisa melhorar\u0026#34; } fun descreverTipo(valor: Any): String = when (valor) { is String -\u0026gt; \u0026#34;É uma String: $valor\u0026#34; is Int -\u0026gt; \u0026#34;É um inteiro: $valor\u0026#34; is List\u0026lt;*\u0026gt; -\u0026gt; \u0026#34;É uma lista com ${valor.size} elementos\u0026#34; else -\u0026gt; \u0026#34;Tipo desconhecido\u0026#34; } Como começar a estudar Kotlin Se bateu aquela vontade de aprender, aqui vai um roteiro prático:\nInstale o IntelliJ IDEA Community (gratuito) ou use o Kotlin Playground online Faça os Kotlin Koans — exercícios interativos oficiais da JetBrains Leia a documentação oficial em kotlinlang.org Crie um projetinho pessoal — nada melhor pra fixar do que colocar a mão na massa Acompanhe o Kotlin Brasil — aqui a gente traz conteúdo fresquinho em português toda semana Onde Kotlin é usado? Kotlin não é só pra Android. Veja onde a linguagem brilha:\nAndroid: linguagem oficial recomendada pelo Google, usada por mais de 95% dos top 1000 apps da Play Store Backend: com Spring Boot, Ktor, Quarkus e Micronaut — grandes empresas como Nubank, Mercado Livre e iFood usam Kotlin no servidor Multiplataforma: Kotlin Multiplatform (KMP) permite compartilhar lógica de negócio entre Android, iOS, web e desktop com um único código-base Scripting: automação de tarefas com scripts .kts, incluindo build scripts do Gradle (build.gradle.kts) Data Science: com bibliotecas como Kotlin DataFrame, KotlinDL e integração com Jupyter Notebooks via Kotlin Kernel Desenvolvimento web: Kotlin/JS permite compilar Kotlin para JavaScript, incluindo integração com frameworks como React via wrappers oficiais Comunidade e Ecossistema Uma das grandes forças do Kotlin é sua comunidade ativa e acolhedora. A KotlinConf, conferência oficial organizada pela JetBrains, reúne milhares de desenvolvedores todos os anos e é o principal evento do ecossistema. Além dela, existem diversos meetups e comunidades locais ao redor do mundo, inclusive no Brasil.\nO Kotlin Slack oficial conta com centenas de milhares de membros e é um dos melhores lugares para tirar dúvidas e trocar experiências. A linguagem também tem forte presença no Stack Overflow, GitHub e Reddit. A JetBrains mantém uma cadência consistente de lançamentos, com atualizações regulares que trazem novos recursos e melhorias de desempenho. O ecossistema de bibliotecas e ferramentas cresce a cada ano, com projetos como Ktor, Exposed, kotlinx.serialization e Compose Multiplatform ganhando cada vez mais adoção.\nPara quem está no Brasil, acompanhar comunidades em português é uma ótima forma de se manter atualizado e fazer networking com outros desenvolvedores que usam Kotlin no dia a dia.\nConclusão Kotlin é uma linguagem moderna, segura e produtiva que conquistou desenvolvedores no mundo inteiro — e no Brasil não é diferente. Se você está pensando em aprender uma nova linguagem, Kotlin é uma escolha certeira. Outras linguagens modernas que vale conhecer incluem Go, Rust e Python — cada uma com seus pontos fortes.\nNos próximos posts, vamos mergulhar mais fundo em cada recurso que mencionamos aqui. Fique ligado no Kotlin Brasil e bons estudos!\n","permalink":"https://kotlin.dev.br/blog/o-que-e-kotlin/","summary":"\u003cp\u003eSe você está começando no mundo da programação ou já manja de Java e quer conhecer algo mais moderno, este guia é pra você. Vamos explorar tudo sobre Kotlin — do zero ao primeiro código rodando.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-kotlin\"\u003eO que é Kotlin?\u003c/h2\u003e\n\u003cp\u003eKotlin é uma linguagem de programação criada pela JetBrains (a mesma empresa por trás do IntelliJ IDEA) e lançada oficialmente em 2016. Desde 2019, o Google a considera a linguagem preferencial para desenvolvimento Android, e desde então ela só cresceu.\u003c/p\u003e","title":"O que É Kotlin: Guia Completo em Português | Kotlin Brasil"},{"content":"Sobre a vagaA Platform Science busca um(a) Engenheiro(a) Mobile Júnior para atuar presencialmente em Londrina, Paraná.\nInformações principaisSenioridade: Júnior / nível inicialModelo de trabalho: PresencialLocal: Londrina, Paraná, BrasilObservaçãoA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos, stack técnica ou benefícios.\n","permalink":"https://kotlin.dev.br/vagas/aq4niclu25ii2nsm-platform-science-engenheiro-a-mobile-junior/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Platform Science busca um(a) Engenheiro(a) Mobile Júnior para atuar presencialmente em Londrina, Paraná.\u003c/p\u003e\u003ch3\u003eInformações principais\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eSenioridade:\u003c/strong\u003e Júnior / nível inicial\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eModelo de trabalho:\u003c/strong\u003e Presencial\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eLocal:\u003c/strong\u003e Londrina, Paraná, Brasil\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eObservação\u003c/h3\u003e\u003cp\u003eA descrição original não trouxe detalhes adicionais sobre responsabilidades, requisitos, stack técnica ou benefícios.\u003c/p\u003e","title":"Engenheiro(a) Mobile Júnior"},{"content":"O que são Collections em Kotlin? Collections (coleções) são estruturas que agrupam múltiplos elementos. Em Kotlin, existem três tipos principais: List (lista ordenada), Set (conjunto sem duplicatas) e Map (mapeamento chave-valor). Cada uma vem em versão imutável (padrão) e mutável.\nImagine que você está organizando uma estante de livros. Uma List seria como uma prateleira numerada, onde cada livro tem uma posição fixa. Um Set seria como uma coleção de selos únicos \u0026ndash; não faz sentido ter dois selos idênticos. Já um Map funcionaria como um dicionário, onde cada palavra (chave) aponta para sua definição (valor).\nA grande vantagem das collections em Kotlin sobre outras linguagens é a combinação de imutabilidade por padrão com um conjunto rico de funções de ordem superior que permitem transformar dados de forma declarativa e concisa.\nCriando coleções fun main() { // Imutáveis (somente leitura) val nomes = listOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;, \u0026#34;Carla\u0026#34;) val ids = setOf(1, 2, 3, 2) // {1, 2, 3} — sem duplicata val capitais = mapOf(\u0026#34;SP\u0026#34; to \u0026#34;São Paulo\u0026#34;, \u0026#34;RJ\u0026#34; to \u0026#34;Rio de Janeiro\u0026#34;) // Mutáveis val tarefas = mutableListOf(\u0026#34;Estudar\u0026#34;, \u0026#34;Codar\u0026#34;) tarefas.add(\u0026#34;Descansar\u0026#34;) } Operações funcionais A grande força das coleções em Kotlin são as operações funcionais encadeadas:\ndata class Produto(val nome: String, val preco: Double, val categoria: String) fun main() { val produtos = listOf( Produto(\u0026#34;Notebook\u0026#34;, 4500.0, \u0026#34;Tech\u0026#34;), Produto(\u0026#34;Caderno\u0026#34;, 25.0, \u0026#34;Papelaria\u0026#34;), Produto(\u0026#34;Mouse\u0026#34;, 120.0, \u0026#34;Tech\u0026#34;), Produto(\u0026#34;Caneta\u0026#34;, 5.0, \u0026#34;Papelaria\u0026#34;), Produto(\u0026#34;Monitor\u0026#34;, 1800.0, \u0026#34;Tech\u0026#34;) ) // Filtrar, transformar e ordenar val techBaratos = produtos .filter { it.categoria == \u0026#34;Tech\u0026#34; } .filter { it.preco \u0026lt; 2000 } .sortedBy { it.preco } .map { \u0026#34;${it.nome}: R$ ${it.preco}\u0026#34; } techBaratos.forEach { println(it) } // Mouse: R$ 120.0 // Monitor: R$ 1800.0 } Operações úteis fun main() { val numeros = listOf(3, 1, 4, 1, 5, 9, 2, 6) println(numeros.sum()) // 31 println(numeros.average()) // 3.875 println(numeros.max()) // 9 println(numeros.distinct()) // [3, 1, 4, 5, 9, 2, 6] println(numeros.take(3)) // [3, 1, 4] println(numeros.any { it \u0026gt; 5 }) // true println(numeros.all { it \u0026gt; 0 }) // true } Agrupando e associando data class Aluno(val nome: String, val turma: String) fun main() { val alunos = listOf( Aluno(\u0026#34;Fernanda\u0026#34;, \u0026#34;A\u0026#34;), Aluno(\u0026#34;Lucas\u0026#34;, \u0026#34;B\u0026#34;), Aluno(\u0026#34;Mariana\u0026#34;, \u0026#34;A\u0026#34;), Aluno(\u0026#34;Pedro\u0026#34;, \u0026#34;B\u0026#34;) ) val porTurma = alunos.groupBy { it.turma } porTurma.forEach { (turma, lista) -\u0026gt; println(\u0026#34;Turma $turma: ${lista.map { it.nome }}\u0026#34;) } // Turma A: [Fernanda, Mariana] // Turma B: [Lucas, Pedro] } Collections em Kotlin são expressivas e poderosas. Com as operações funcionais, você resolve em poucas linhas o que em outras linguagens exigiria loops verbosos.\nTransformações avançadas com flatMap e zip Além das operações básicas, Kotlin oferece funções poderosas para cenários mais elaborados:\ndata class Pedido(val cliente: String, val itens: List\u0026lt;String\u0026gt;) fun main() { val pedidos = listOf( Pedido(\u0026#34;Ana\u0026#34;, listOf(\u0026#34;Pizza\u0026#34;, \u0026#34;Suco\u0026#34;)), Pedido(\u0026#34;Bruno\u0026#34;, listOf(\u0026#34;Hambúrguer\u0026#34;, \u0026#34;Batata\u0026#34;, \u0026#34;Refrigerante\u0026#34;)) ) // flatMap achata listas aninhadas val todosItens = pedidos.flatMap { it.itens } println(todosItens) // [Pizza, Suco, Hambúrguer, Batata, Refrigerante] // zip combina duas listas em pares val funcionários = listOf(\u0026#34;Carlos\u0026#34;, \u0026#34;Diana\u0026#34;, \u0026#34;Eduardo\u0026#34;) val cargos = listOf(\u0026#34;Dev\u0026#34;, \u0026#34;QA\u0026#34;, \u0026#34;DevOps\u0026#34;) val equipe = funcionários.zip(cargos) { nome, cargo -\u0026gt; \u0026#34;$nome ($cargo)\u0026#34; } println(equipe) // [Carlos (Dev), Diana (QA), Eduardo (DevOps)] } Usando fold e reduce para cálculos Quando você precisa acumular valores de uma coleção, fold e reduce são essenciais:\ndata class ItemCarrinho(val nome: String, val preco: Double, val quantidade: Int) fun main() { val carrinho = listOf( ItemCarrinho(\u0026#34;Camiseta\u0026#34;, 79.90, 2), ItemCarrinho(\u0026#34;Calça\u0026#34;, 149.90, 1), ItemCarrinho(\u0026#34;Tênis\u0026#34;, 299.90, 1) ) val total = carrinho.fold(0.0) { acumulador, item -\u0026gt; acumulador + (item.preco * item.quantidade) } println(\u0026#34;Total: R$ $total\u0026#34;) // Total: R$ 609.6 // Partition separa em dois grupos val (caros, baratos) = carrinho.partition { it.preco \u0026gt; 100 } println(\u0026#34;Caros: ${caros.map { it.nome }}\u0026#34;) // [Calça, Tênis] println(\u0026#34;Baratos: ${baratos.map { it.nome }}\u0026#34;) // [Camiseta] } Casos de Uso no Mundo Real Processamento de respostas de API: ao receber uma lista de objetos JSON, use map para converter em data classes e filter para selecionar apenas os dados relevantes. Relatórios e dashboards: groupBy, sumOf e associate permitem agregar dados para gerar relatórios sem precisar de SQL. Validação de formulários: use all para verificar se todos os campos estão preenchidos ou any para detectar se há algum erro. Sistemas de busca: combine filter, sortedBy e take para implementar buscas com ranking e paginação. Processamento em lote: chunked e windowed dividem listas grandes em blocos menores para processamento paralelo ou em batches. Boas Práticas Prefira coleções imutáveis: use listOf, setOf e mapOf como padrão. Só use versões mutáveis quando realmente precisar modificar a coleção. Encadeie operações funcionais em vez de usar loops for com variáveis mutáveis. O código fica mais legível e menos propenso a erros. Use Sequence para coleções grandes: quando encadeia muitas operações em coleções com milhares de itens, converta para sequence com .asSequence() para evitar criar listas intermediárias. Evite acessar índices diretamente com get() ou [] sem verificar o tamanho. Prefira getOrNull(), firstOrNull() ou find. Não misture lógica de negócio com transformações: extraia lambdas complexas para funções nomeadas. Erros Comuns Tentar modificar uma coleção imutável: chamar add() ou remove() em uma List retornada por listOf() causa UnsupportedOperationException. Se precisar modificar, use mutableListOf() ou crie uma nova lista com operações como + ou filter. Confundir map com forEach: map transforma e retorna uma nova lista; forEach apenas executa uma ação para cada item sem retorno. Usar map quando você não precisa do resultado desperdiça memória. Ignorar a diferença entre List e MutableList em parâmetros: se uma função recebe MutableList, quem chama fica preso a esse tipo. Prefira receber List e retornar List. Encadear muitas operações sem asSequence(): cada operação como filter e map cria uma lista intermediária. Para coleções grandes, isso pode causar problemas de performance. Perguntas Frequentes Qual a diferença entre List e Array em Kotlin? List é uma interface de coleção com operações funcionais ricas e imutabilidade por padrão. Array é um wrapper sobre arrays do Java, com tamanho fixo. Na maioria dos casos, prefira List.\nQuando devo usar Set em vez de List? Use Set quando a unicidade dos elementos é importante e você não precisa de ordem de inserção garantida. Verificar se um elemento existe em um Set é O(1), enquanto em uma List é O(n).\nO que é Sequence e quando usar? Sequence processa elementos de forma preguiçosa (lazy), um por um, em vez de criar listas intermediárias a cada operação. Use quando tiver coleções grandes (milhares de itens) com múltiplas transformações encadeadas.\nPosso converter entre tipos de coleção? Sim. Use toList(), toSet(), toMap(), toMutableList() e variantes para converter entre qualquer tipo de coleção. Também é possível usar associate e groupBy para criar mapas a partir de listas.\n","permalink":"https://kotlin.dev.br/glossario/collections/","summary":"\u003ch2 id=\"o-que-são-collections-em-kotlin\"\u003eO que são Collections em Kotlin?\u003c/h2\u003e\n\u003cp\u003eCollections (coleções) são estruturas que agrupam múltiplos elementos. Em Kotlin, existem três tipos principais: \u003cstrong\u003eList\u003c/strong\u003e (lista ordenada), \u003cstrong\u003eSet\u003c/strong\u003e (conjunto sem duplicatas) e \u003cstrong\u003eMap\u003c/strong\u003e (mapeamento chave-valor). Cada uma vem em versão \u003cstrong\u003eimutável\u003c/strong\u003e (padrão) e \u003cstrong\u003emutável\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eImagine que você está organizando uma estante de livros. Uma \u003cstrong\u003eList\u003c/strong\u003e seria como uma prateleira numerada, onde cada livro tem uma posição fixa. Um \u003cstrong\u003eSet\u003c/strong\u003e seria como uma coleção de selos únicos \u0026ndash; não faz sentido ter dois selos idênticos. Já um \u003cstrong\u003eMap\u003c/strong\u003e funcionaria como um dicionário, onde cada palavra (chave) aponta para sua definição (valor).\u003c/p\u003e","title":"Collections em Kotlin: O que São e Como Usar | Kotlin Brasil"},{"content":"O que é when em Kotlin? O when é a versão turbinada do switch em Kotlin. Ele funciona tanto como expressão (retorna valor) quanto como instrução (executa blocos). É mais poderoso e flexível que o switch de Java ou C — suporta ranges, verificações de tipo, condições complexas é muito mais.\nSintaxe básica fun classificarNota(nota: Int): String { return when (nota) { 10 -\u0026gt; \u0026#34;Perfeito!\u0026#34; in 7..9 -\u0026gt; \u0026#34;Aprovado\u0026#34; in 5..6 -\u0026gt; \u0026#34;Recuperação\u0026#34; in 0..4 -\u0026gt; \u0026#34;Reprovado\u0026#34; else -\u0026gt; \u0026#34;Nota invalida\u0026#34; } } fun main() { println(classificarNota(8)) // Aprovado println(classificarNota(3)) // Reprovado } When como expressão Quando when é usado como expressão (retornando valor), o else é obrigatório — a menos que o compilador consiga verificar que todos os casos estão cobertos:\nenum class DiaSemana { SEG, TER, QUA, QUI, SEX, SAB, DOM } fun tipoDeDia(dia: DiaSemana) = when (dia) { DiaSemana.SEG, DiaSemana.TER, DiaSemana.QUA, DiaSemana.QUI, DiaSemana.SEX -\u0026gt; \u0026#34;Dia util\u0026#34; DiaSemana.SAB, DiaSemana.DOM -\u0026gt; \u0026#34;Fim de semana\u0026#34; } Verificação de tipo com is fun descrever(obj: Any): String = when (obj) { is String -\u0026gt; \u0026#34;Texto com ${obj.length} caracteres\u0026#34; is Int -\u0026gt; \u0026#34;Número inteiro: $obj\u0026#34; is List\u0026lt;*\u0026gt; -\u0026gt; \u0026#34;Lista com ${obj.size} itens\u0026#34; is Boolean -\u0026gt; if (obj) \u0026#34;Verdadeiro\u0026#34; else \u0026#34;Falso\u0026#34; else -\u0026gt; \u0026#34;Tipo desconhecido\u0026#34; } fun main() { println(descrever(\u0026#34;Kotlin\u0026#34;)) // Texto com 6 caracteres println(descrever(42)) // Número inteiro: 42 println(descrever(listOf(1, 2, 3))) // Lista com 3 itens } Repare que dentro de cada branch, o smart cast já aplica o tipo automaticamente.\nWhen sem argumento Você pode usar when sem argumento, funcionando como uma cadeia de if-else:\nfun avaliarTemperatura(temp: Double): String = when { temp \u0026lt; 0 -\u0026gt; \u0026#34;Congelante!\u0026#34; temp \u0026lt; 15 -\u0026gt; \u0026#34;Tá frio, hein\u0026#34; temp \u0026lt; 25 -\u0026gt; \u0026#34;Temperatura agradável\u0026#34; temp \u0026lt; 35 -\u0026gt; \u0026#34;Tá quente\u0026#34; else -\u0026gt; \u0026#34;Derretendo!\u0026#34; } fun main() { println(avaliarTemperatura(28.0)) // Tá quente } When com sealed class A combinação com sealed class é perfeita — o compilador garante que todos os casos são tratados, sem precisar de else. Essa é uma das duplas mais poderosas do Kotlin pra modelar estados e resultados.\nsealed class Resultado { data class Sucesso(val dados: String) : Resultado() data class Erro(val mensagem: String) : Resultado() data object Carregando : Resultado() } fun tratarResultado(resultado: Resultado): String = when (resultado) { is Resultado.Sucesso -\u0026gt; \u0026#34;Dados recebidos: ${resultado.dados}\u0026#34; is Resultado.Erro -\u0026gt; \u0026#34;Falha: ${resultado.mensagem}\u0026#34; is Resultado.Carregando -\u0026gt; \u0026#34;Aguarde, carregando...\u0026#34; } fun main() { val r1 = Resultado.Sucesso(\u0026#34;Lista de usuários\u0026#34;) val r2 = Resultado.Erro(\u0026#34;Timeout na conexão\u0026#34;) val r3 = Resultado.Carregando println(tratarResultado(r1)) // Dados recebidos: Lista de usuários println(tratarResultado(r2)) // Falha: Timeout na conexão println(tratarResultado(r3)) // Aguarde, carregando... } Como Resultado é uma sealed class, o compilador sabe que existem exatamente três subtipos. Se você adicionar um novo subtipo no futuro, o compilador vai avisar em todos os when que ficaram incompletos.\nWhen com múltiplas condições e guardas A partir do Kotlin 1.9, o when ganhou suporte a guard conditions, que permitem adicionar condições extras a cada branch usando if.\nfun classificarIdade(idade: Int, temDocumento: Boolean): String = when { idade \u0026lt; 0 -\u0026gt; \u0026#34;Idade invalida\u0026#34; idade \u0026lt; 12 -\u0026gt; \u0026#34;Criança\u0026#34; idade \u0026lt; 18 \u0026amp;\u0026amp; temDocumento -\u0026gt; \u0026#34;Adolescente com documento\u0026#34; idade \u0026lt; 18 -\u0026gt; \u0026#34;Adolescente sem documento\u0026#34; idade \u0026lt; 60 -\u0026gt; \u0026#34;Adulto\u0026#34; else -\u0026gt; \u0026#34;Idoso\u0026#34; } fun main() { println(classificarIdade(15, true)) // Adolescente com documento println(classificarIdade(15, false)) // Adolescente sem documento println(classificarIdade(45, true)) // Adulto } Casos de Uso no Mundo Real Tratamento de respostas HTTP: O when é ideal para tratar diferentes códigos de status HTTP. Você pode agrupar ranges como in 200..299 para sucesso, in 400..499 para erros do cliente e in 500..599 para erros do servidor, tornando o código muito mais legível do que uma cadeia de if-else. Navegação em aplicativos Android: Em apps com Jetpack Compose ou Fragments, o when combinado com sealed classes é o padrão para decidir qual tela exibir com base no estado atual de navegação. Parsing de formatos de dados: Ao processar dados de diferentes formatos (JSON, XML, CSV), o when com verificação de tipo (is) permite tratar cada formato de maneira específica com smart cast automático. Máquinas de estado: Sistemas como processamento de pedidos (novo, pago, enviado, entregue, cancelado) se beneficiam enormemente do when com sealed classes, garantindo que toda transição de estado é tratada explicitamente. Boas Práticas Prefira when como expressão: Sempre que possível, use when retornando um valor diretamente com val resultado = when { ... }. Isso elimina a necessidade de variáveis mutáveis e torna o código mais funcional. Use sealed classes em vez de else: Quando você tem um conjunto fixo de tipos ou estados, modele-os com sealed classes. O compilador vai garantir que todos os casos sejam tratados, e qualquer novo caso adicionado no futuro será detectado em tempo de compilação. Agrupe valores relacionados: O when permite agrupar múltiplos valores na mesma branch usando vírgula, como 'a', 'e', 'i', 'o', 'u' -\u0026gt; \u0026quot;vogal\u0026quot;. Use isso para evitar duplicação de lógica. Prefira when a cadeias longas de if-else: Quando você tem três ou mais condições sobre o mesmo valor, when é quase sempre mais legível e menos propenso a erros do que if-else if-else. Aproveite o smart cast: Dentro de branches com is, o Kotlin já faz o cast automaticamente. Não use as manualmente após verificar o tipo com is — isso é redundante e polui o código. Erros Comuns Esquecer o else em expressões when: Quando when é usado como expressão (retornando valor), o else é obrigatório se os casos não são exaustivos. O compilador vai apontar o erro, mas é comum esquecer durante a escrita inicial. Ordem errada dos branches: O when avalia os branches de cima para baixo e executa o primeiro que corresponder. Se você colocar um branch mais genérico antes de um mais específico, o específico nunca será alcançado. Por exemplo, is Number antes de is Int faz com que inteiros caiam sempre no branch de Number. Não aproveitar ranges: Escrever 1 -\u0026gt; ..., 2 -\u0026gt; ..., 3 -\u0026gt; ... quando todos retornam o mesmo valor é desnecessário. Use in 1..3 -\u0026gt; ... para simplificar. O mesmo vale para verificações como \u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;, \u0026quot;c\u0026quot; -\u0026gt; .... Usar when para apenas dois casos: Se você tem apenas duas opções (verdadeiro/falso, presente/ausente), um simples if-else é mais claro e conciso do que um when. Use when quando há três ou mais caminhos. Não tratar todos os casos de um enum: Mesmo quando o when é usado como instrução (sem retornar valor), é boa prática tratar todos os valores do enum. Isso evita bugs silenciosos quando novos valores são adicionados ao enum no futuro. Perguntas Frequentes when substitui completamente o switch do Java? Sim, e vai muito além. O when do Kotlin suporta verificação de tipo com is, ranges com in, condições arbitrárias (quando usado sem argumento), e funciona como expressão. O switch do Java é limitado a valores constantes de tipos primitivos, enums e strings.\nPosso usar when sem chaves nas branches? Sim. Se a branch tem apenas uma expressão, não precisa de chaves: 10 -\u0026gt; \u0026quot;dez\u0026quot;. Mas se precisa de múltiplas instruções, envolva com chaves e a última expressão será o valor de retorno da branch.\nO when é mais performático que if-else? Depende do caso. Para comparações com valores constantes de Int ou String, o compilador pode gerar um tableswitch ou lookupswitch no bytecode, que é mais eficiente que uma série de comparações. Para condições complexas ou when sem argumento, a performance é equivalente a if-else.\nComo funciona o when com valor de retorno em blocos? Quando uma branch do when usa chaves para múltiplas instruções, a última expressão do bloco é o valor retornado. Por exemplo: in 1..10 -\u0026gt; { println(\u0026quot;Processando\u0026quot;); \u0026quot;válido\u0026quot; } retorna \u0026quot;válido\u0026quot;.\nTermos Relacionados Sealed Class — Classes seladas que combinam perfeitamente com when para garantir exaustividade. Enum — Enumerações que permitem when exaustivo sem else. val — Variáveis somente leitura, ideais para receber o resultado de uma expressão when. Smart Cast — O mecanismo que permite usar o tipo verificado com is dentro das branches do when. ","permalink":"https://kotlin.dev.br/glossario/when/","summary":"\u003ch2 id=\"o-que-é-when-em-kotlin\"\u003eO que é \u003ccode\u003ewhen\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO \u003ccode\u003ewhen\u003c/code\u003e é a versão turbinada do \u003ccode\u003eswitch\u003c/code\u003e em Kotlin. Ele funciona tanto como \u003cstrong\u003eexpressão\u003c/strong\u003e (retorna valor) quanto como \u003cstrong\u003einstrução\u003c/strong\u003e (executa blocos). É mais poderoso e flexível que o switch de Java ou C — suporta ranges, verificações de tipo, condições complexas é muito mais.\u003c/p\u003e\n\u003ch3 id=\"sintaxe-básica\"\u003eSintaxe básica\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003eclassificarNota\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enota\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"k\"\u003ewhen\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enota\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"m\"\u003e10\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Perfeito!\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ein\u003c/span\u003e \u003cspan class=\"m\"\u003e7.\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"m\"\u003e9\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Aprovado\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ein\u003c/span\u003e \u003cspan class=\"m\"\u003e5.\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"m\"\u003e6\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Recuperação\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ein\u003c/span\u003e \u003cspan class=\"m\"\u003e0.\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Reprovado\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Nota invalida\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eclassificarNota\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e  \u003cspan class=\"c1\"\u003e// Aprovado\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eclassificarNota\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e  \u003cspan class=\"c1\"\u003e// Reprovado\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"when-como-expressão\"\u003eWhen como expressão\u003c/h3\u003e\n\u003cp\u003eQuando \u003ccode\u003ewhen\u003c/code\u003e é usado como expressão (retornando valor), o \u003ccode\u003eelse\u003c/code\u003e é obrigatório — a menos que o compilador consiga verificar que todos os casos estão cobertos:\u003c/p\u003e","title":"When em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que e Destructuring em Kotlin? Destructuring (desestruturacao) permite decompor um objeto em várias variaveis numa única declaracao. Em vez de acessar cada propriedade separadamente, você extrai tudo de uma vez. E prático, limpo é muito usado no dia a dia.\nImagine que você recebe uma encomenda com vários itens dentro de uma caixa. Em vez de abrir a caixa e tirar item por item chamando pelo nome da caixa toda vez, o destructuring e como abrir a caixa e já colocar cada item diretamente na prateleira certa. Voce ganha clareza e economia de código.\nEsse recurso funciona com data classes, pares, triplas, mapas e qualquer classe que implemente as funções componentN(). E uma ferramenta essencial para quem trabalha com colecoes e lambdas em Kotlin.\nSintaxe básica com Data Class data class Endereco(val rua: String, val cidade: String, val estado: String) fun main() { val endereco = Endereco(\u0026#34;Rua das Flores\u0026#34;, \u0026#34;Recife\u0026#34;, \u0026#34;PE\u0026#34;) val (rua, cidade, estado) = endereco println(\u0026#34;$rua, $cidade - $estado\u0026#34;) // Rua das Flores, Recife - PE } Funciona porque data classes geram automaticamente as funções component1(), component2(), etc.\nDestructuring em Maps Uma das situacoes mais comuns e iterar sobre mapas:\nfun main() { val capitais = mapOf( \u0026#34;SP\u0026#34; to \u0026#34;Sao Paulo\u0026#34;, \u0026#34;RJ\u0026#34; to \u0026#34;Rio de Janeiro\u0026#34;, \u0026#34;BA\u0026#34; to \u0026#34;Salvador\u0026#34; ) for ((sigla, capital) in capitais) { println(\u0026#34;$sigla -\u0026gt; $capital\u0026#34;) } } Bem mais legivel do que acessar entry.key e entry.value, concorda?\nDestructuring em lambdas fun main() { val pessoas = listOf( Pair(\u0026#34;Ana\u0026#34;, 25), Pair(\u0026#34;Bruno\u0026#34;, 30), Pair(\u0026#34;Carla\u0026#34;, 28) ) pessoas.forEach { (nome, idade) -\u0026gt; println(\u0026#34;$nome tem $idade anos\u0026#34;) } } Ignorando variaveis com _ Se não precisa de algum componente, use _ pra ignorar:\ndata class Transacao(val id: String, val valor: Double, val data: String) fun main() { val transacao = Transacao(\u0026#34;TX-001\u0026#34;, 150.0, \u0026#34;2026-02-15\u0026#34;) val (_, valor, _) = transacao println(\u0026#34;Valor: R$ $valor\u0026#34;) // Valor: R$ 150.0 } Criando destructuring em classes proprias Para classes que não sao data class, basta implementar as funções operator componentN():\nclass Coordenada(val latitude: Double, val longitude: Double) { operator fun component1() = latitude operator fun component2() = longitude } fun main() { val (lat, lng) = Coordenada(-8.0476, -34.8770) println(\u0026#34;Lat: $lat, Lng: $lng\u0026#34;) } Retornando múltiplos valores Destructuring combina bem com Pair e Triple pra retornar vários valores de uma função:\nfun dividir(a: Int, b: Int): Pair\u0026lt;Int, Int\u0026gt; { return Pair(a / b, a % b) } fun main() { val (quociente, resto) = dividir(17, 5) println(\u0026#34;Quociente: $quociente, Resto: $resto\u0026#34;) } Destructuring com resultados de funções da stdlib Destructuring se integra muito bem com funções da biblioteca padrão do Kotlin, como withIndex() e partition():\nfun main() { val frutas = listOf(\u0026#34;manga\u0026#34;, \u0026#34;acerola\u0026#34;, \u0026#34;caju\u0026#34;, \u0026#34;goiaba\u0026#34;, \u0026#34;pitanga\u0026#34;) // withIndex retorna IndexedValue, que suporta destructuring for ((indice, fruta) in frutas.withIndex()) { println(\u0026#34;$indice: $fruta\u0026#34;) } // partition retorna um Pair de listas val (curtas, longas) = frutas.partition { it.length \u0026lt;= 4 } println(\u0026#34;Nomes curtos: $curtas\u0026#34;) // [caju] println(\u0026#34;Nomes longos: $longas\u0026#34;) // [manga, acerola, goiaba, pitanga] } Destructuring em blocos try-catch com Result Voce pode usar destructuring para lidar com respostas de APIs ou operações que retornam dados estruturados:\ndata class RespostaApi(val sucesso: Boolean, val mensagem: String, val dados: Map\u0026lt;String, Any\u0026gt;) fun buscarUsuario(id: Int): RespostaApi { return if (id \u0026gt; 0) { RespostaApi(true, \u0026#34;Encontrado\u0026#34;, mapOf(\u0026#34;nome\u0026#34; to \u0026#34;Maria\u0026#34;, \u0026#34;idade\u0026#34; to 32)) } else { RespostaApi(false, \u0026#34;Nao encontrado\u0026#34;, emptyMap()) } } fun main() { val (sucesso, mensagem, dados) = buscarUsuario(1) if (sucesso) { println(\u0026#34;$mensagem: $dados\u0026#34;) } } Casos de Uso no Mundo Real Processamento de arquivos CSV: ao ler linhas de um CSV, você pode desestruturar cada linha em variaveis nomeadas como val (nome, email, telefone) = linha.split(\u0026quot;,\u0026quot;), tornando o código muito mais legivel. Respostas de APIs: quando uma função retorna um par de status e corpo da resposta, destructuring permite extrair ambos numa única linha. Iteracao sobre bancos de dados: ao percorrer resultados de queries que retornam mapas ou data classes, você acessa cada campo diretamente. Testes unitarios: ao validar objetos complexos, desestruturar facilita a comparacao de campos individuais sem criar variaveis intermediarias. Boas Praticas Use destructuring quando os nomes das variaveis deixam claro o que cada componente representa. Se os nomes não ajudam, considere acessar as propriedades diretamente. Prefira data classes em vez de Pair e Triple quando o significado dos campos importa. Pair(\u0026quot;Ana\u0026quot;, 25) não diz o que e cada campo; Pessoa(\u0026quot;Ana\u0026quot;, 25) sim. Use _ para ignorar componentes que você não precisa, evitando variaveis não utilizadas. Nao desestruture objetos com muitos campos (mais de 4 ou 5) numa única declaracao, pois fica difícil acompanhar a ordem. Erros Comuns Confundir a ordem dos componentes: o destructuring segue a ordem de declaracao das propriedades. Se você inverter val (cidade, rua) = endereco, vai receber os valores trocados sem nenhum erro de compilação. Tentar desestruturar classes que não sao data class: classes comuns não geram componentN() automaticamente. Voce precisa implementar essas funções manualmente ou usar uma data class. Ignorar o tipo: se você desestruturar um Pair\u0026lt;String, Int\u0026gt; e tratar o segundo valor como String, tera um erro em tempo de execução. Esquecer o val ou var: a declaracao (a, b) = par sem val na frente não funciona como declaracao; e necessário escrever val (a, b) = par. Perguntas Frequentes Destructuring funciona com classes que não sao data class? Sim, desde que você implemente as funções operator fun componentN() na classe. Data classes geram essas funções automaticamente, mas nada impede você de cria-las manualmente em qualquer classe.\nPosso usar destructuring com sealed classes? Sim, desde que a sealed class ou suas subclasses sejam data classes ou implementem as funções componentN(). Geralmente você faz o when primeiro e depois desestrutura dentro de cada branch.\nExiste limite de componentes no destructuring? Nao existe um limite imposto pela linguagem, mas na prática, data classes geram component1() até componentN() para todas as propriedades do construtor primario. O bom senso recomenda não ultrapassar 4 ou 5 componentes.\nDestructuring cria copias dos valores ou referência o objeto original? Destructuring cria variaveis independentes com os valores retornados pelas funções componentN(). Para tipos primitivos, sao copias. Para objetos, sao referências ao mesmo objeto em memória.\nDestructuring e um recurso simples que faz uma diferenca enorme na legibilidade do código Kotlin.\n","permalink":"https://kotlin.dev.br/glossario/destructuring/","summary":"\u003ch2 id=\"o-que-e-destructuring-em-kotlin\"\u003eO que e Destructuring em Kotlin?\u003c/h2\u003e\n\u003cp\u003eDestructuring (desestruturacao) permite \u003cstrong\u003edecompor um objeto em várias variaveis\u003c/strong\u003e numa única declaracao. Em vez de acessar cada propriedade separadamente, você extrai tudo de uma vez. E prático, limpo é muito usado no dia a dia.\u003c/p\u003e\n\u003cp\u003eImagine que você recebe uma encomenda com vários itens dentro de uma caixa. Em vez de abrir a caixa e tirar item por item chamando pelo nome da caixa toda vez, o destructuring e como abrir a caixa e já colocar cada item diretamente na prateleira certa. Voce ganha clareza e economia de código.\u003c/p\u003e","title":"Destructuring em Kotlin: O que E e Como Funciona | Kotlin Brasil"},{"content":"O que é Operator Overloading em Kotlin? Operator Overloading (sobrecarga de operadores) permite redefinir o comportamento de operadores como +, -, *, [], == e outros para suas próprias classes. Você escreve funções especiais marcadas com operator e pronto — seus objetos passam a funcionar com a sintaxe natural de operadores.\nExemplo básico: somando vetores data class Vetor(val x: Double, val y: Double) { operator fun plus(outro: Vetor) = Vetor(x + outro.x, y + outro.y) operator fun minus(outro: Vetor) = Vetor(x - outro.x, y - outro.y) operator fun times(escalar: Double) = Vetor(x * escalar, y * escalar) } fun main() { val a = Vetor(1.0, 2.0) val b = Vetor(3.0, 4.0) println(a + b) // Vetor(x=4.0, y=6.0) println(a - b) // Vetor(x=-2.0, y=-2.0) println(a * 3.0) // Vetor(x=3.0, y=6.0) } Principais operadores Operador Função Exemplo + plus a + b - minus a - b * times a * b / div a / b [] get / set a[i] == equals a == b \u0026gt; \u0026lt; compareTo a \u0026gt; b in contains x in a Operadores de acesso: get e set class Matriz(private val dados: Array\u0026lt;IntArray\u0026gt;) { operator fun get(linha: Int, coluna: Int): Int = dados[linha][coluna] operator fun set(linha: Int, coluna: Int, valor: Int) { dados[linha][coluna] = valor } } fun main() { val m = Matriz(arrayOf(intArrayOf(1, 2), intArrayOf(3, 4))) println(m[0, 1]) // 2 m[1, 0] = 99 println(m[1, 0]) // 99 } Operador invoke O operador invoke permite chamar um objeto como se fosse uma função:\nclass Validador(val regex: Regex) { operator fun invoke(valor: String): Boolean = regex.matches(valor) } fun main() { val validarEmail = Validador(Regex(\u0026#34;^[\\\\w.-]+@[\\\\w.-]+\\\\.[a-z]{2,}$\u0026#34;)) println(validarEmail(\u0026#34;karina@kotlin.dev.br\u0026#34;)) // true println(validarEmail(\u0026#34;invalido\u0026#34;)) // false } Operadores de atribuição composta Além dos operadores básicos, você pode sobrecarregar os operadores de atribuição composta como +=, -= e *=. O Kotlin resolve automaticamente a += b como a = a.plus(b) se a variável for var, ou você pode definir plusAssign explicitamente para tipos mutáveis:\nclass Carrinho { private val itens = mutableListOf\u0026lt;String\u0026gt;() operator fun plusAssign(item: String) { itens.add(item) } operator fun minusAssign(item: String) { itens.remove(item) } operator fun contains(item: String): Boolean = item in itens override fun toString() = \u0026#34;Carrinho(itens=$itens)\u0026#34; } fun main() { val carrinho = Carrinho() carrinho += \u0026#34;Teclado\u0026#34; carrinho += \u0026#34;Mouse\u0026#34; carrinho += \u0026#34;Monitor\u0026#34; carrinho -= \u0026#34;Mouse\u0026#34; println(carrinho) // Carrinho(itens=[Teclado, Monitor]) println(\u0026#34;Teclado\u0026#34; in carrinho) // true println(\u0026#34;Mouse\u0026#34; in carrinho) // false } Operadores como extensões Você não precisa ser o dono da classe para definir operadores. Funções de extensão com operator funcionam perfeitamente:\ndata class Dinheiro(val centavos: Long) { override fun toString(): String { val reais = centavos / 100 val cents = centavos % 100 return \u0026#34;R$ $reais,${cents.toString().padStart(2, \u0026#39;0\u0026#39;)}\u0026#34; } } operator fun Dinheiro.plus(outro: Dinheiro) = Dinheiro(centavos + outro.centavos) operator fun Dinheiro.times(quantidade: Int) = Dinheiro(centavos * quantidade) operator fun Dinheiro.compareTo(outro: Dinheiro) = centavos.compareTo(outro.centavos) fun main() { val preco = Dinheiro(2990) // R$ 29,90 val frete = Dinheiro(1500) // R$ 15,00 val total = preco + frete val triplo = preco * 3 println(total) // R$ 44,90 println(triplo) // R$ 89,70 println(preco \u0026gt; frete) // true } Casos de Uso no Mundo Real Cálculos financeiros: criar tipos como Dinheiro ou Moeda com operadores aritméticos, evitando erros de arredondamento com Double e garantindo segurança de tipo. Bibliotecas matemáticas e científicas: definir operações sobre vetores, matrizes, números complexos e outras estruturas algébricas, permitindo que fórmulas no código pareçam com fórmulas matemáticas. DSLs (Domain-Specific Languages): usar invoke, get e contains para criar APIs fluentes e naturais, como builders de consultas SQL ou configurações. Coleções customizadas: sobrecarregar get, set, contains, plusAssign e iterator para criar estruturas de dados com interface familiar. Boas Práticas O operador deve ter um significado intuitivo para quem lê o código. Somar dois vetores faz sentido; \u0026ldquo;somar\u0026rdquo; dois usuários, nem tanto. Mantenha a semântica esperada: plus deve ser comutativo quando possível, compareTo deve ser transitivo, equals deve ser reflexivo, simétrico e transitivo. Prefira operadores como extensões quando a classe não é sua. Isso mantém o código desacoplado e permite adicionar operadores a classes de bibliotecas de terceiros. Documente operadores não óbvios. Se o significado de * na sua classe não for imediatamente claro, adicione um comentário explicando. Evite sobrecarregar operadores em excesso. Se a classe tem dez operadores, talvez ela esteja fazendo coisas demais. Erros Comuns Usar operator overloading sem semântica clara: definir + para concatenar objetos que não fazem sentido juntos confunde outros desenvolvedores e torna o código difícil de manter. Esquecer a palavra-chave operator: sem ela, a função é apenas uma função normal chamada plus ou times, e o operador + ou * não vai funcionar. Confundir plus com plusAssign: se a classe é imutável, defina apenas plus e use var. Se é mutável, defina plusAssign. Definir ambos na mesma classe gera ambiguidade com var. Não respeitar contratos de equals e hashCode: ao sobrecarregar equals, sempre sobrescreva hashCode também. Caso contrário, a classe vai se comportar de forma inesperada em coleções como HashSet e HashMap. Ignorar efeitos colaterais em operadores: operadores devem ser puros quando possível. Um plus que faz chamada de rede ou modifica estado global é um design perigoso. Perguntas Frequentes Posso criar operadores novos que não existem em Kotlin? Não. Kotlin tem um conjunto fixo de operadores que podem ser sobrecarregados. Você não pode inventar símbolos novos como \u0026lt;\u0026gt; ou **. A lista completa está na documentação oficial.\nOperator overloading afeta a performance? Na maioria dos casos, não há impacto significativo. O compilador transforma operadores em chamadas de função normais. Com data class e inline class, o overhead é mínimo ou zero.\nQual a diferença entre == e === ao sobrecarregar? O operador == chama a função equals e pode ser sobrecarregado. Já o === verifica identidade referencial (se dois objetos são a mesma instância na memória) e não pode ser sobrecarregado.\nPosso sobrecarregar operadores em interfaces? Sim. Você pode declarar funções operator em interfaces, e as classes que implementarem a interface terão o operador disponível.\nTermos Relacionados Extension Function — funções de extensão que podem definir operadores para classes existentes Data Class — classes que já implementam equals, hashCode e outros operadores automaticamente Infix Function — outra forma de criar sintaxe expressiva em Kotlin Inline Class — classes wrapper com zero overhead que combinam bem com operadores Quando bem aplicado, operator overloading deixa o código expressivo e natural.\n","permalink":"https://kotlin.dev.br/glossario/operator-overloading/","summary":"\u003ch2 id=\"o-que-é-operator-overloading-em-kotlin\"\u003eO que é Operator Overloading em Kotlin?\u003c/h2\u003e\n\u003cp\u003eOperator Overloading (sobrecarga de operadores) permite \u003cstrong\u003eredefinir o comportamento de operadores\u003c/strong\u003e como \u003ccode\u003e+\u003c/code\u003e, \u003ccode\u003e-\u003c/code\u003e, \u003ccode\u003e*\u003c/code\u003e, \u003ccode\u003e[]\u003c/code\u003e, \u003ccode\u003e==\u003c/code\u003e e outros para suas próprias classes. Você escreve funções especiais marcadas com \u003ccode\u003eoperator\u003c/code\u003e e pronto — seus objetos passam a funcionar com a sintaxe natural de operadores.\u003c/p\u003e\n\u003ch3 id=\"exemplo-básico-somando-vetores\"\u003eExemplo básico: somando vetores\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edata\u003c/span\u003e \u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eVetor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eDouble\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eDouble\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eoperator\u003c/span\u003e \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003eplus\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eoutro\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eVetor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eVetor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e \u003cspan class=\"p\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eoutro\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e \u003cspan class=\"p\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eoutro\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eoperator\u003c/span\u003e \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003eminus\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eoutro\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eVetor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eVetor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e \u003cspan class=\"p\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003eoutro\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e \u003cspan class=\"p\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003eoutro\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eoperator\u003c/span\u003e \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003etimes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eescalar\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eDouble\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eVetor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e \u003cspan class=\"p\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eescalar\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e \u003cspan class=\"p\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eescalar\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003ea\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eVetor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e2.0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003eb\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eVetor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e3.0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e4.0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"p\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e      \u003cspan class=\"c1\"\u003e// Vetor(x=4.0, y=6.0)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"p\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e      \u003cspan class=\"c1\"\u003e// Vetor(x=-2.0, y=-2.0)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"p\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e3.0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e    \u003cspan class=\"c1\"\u003e// Vetor(x=3.0, y=6.0)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"principais-operadores\"\u003ePrincipais operadores\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eOperador\u003c/th\u003e\n          \u003cth\u003eFunção\u003c/th\u003e\n          \u003cth\u003eExemplo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e+\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eplus\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ea + b\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e-\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eminus\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ea - b\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e*\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003etimes\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ea * b\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e/\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ediv\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ea / b\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e[]\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eget\u003c/code\u003e / \u003ccode\u003eset\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ea[i]\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e==\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eequals\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ea == b\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e\u0026gt;\u003c/code\u003e \u003ccode\u003e\u0026lt;\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ecompareTo\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ea \u0026gt; b\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003ein\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003econtains\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ex in a\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"operadores-de-acesso-get-e-set\"\u003eOperadores de acesso: \u003ccode\u003eget\u003c/code\u003e e \u003ccode\u003eset\u003c/code\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eMatriz\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003edados\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eArray\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eIntArray\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eoperator\u003c/span\u003e \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elinha\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecoluna\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003edados\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003elinha\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ecoluna\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eoperator\u003c/span\u003e \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elinha\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecoluna\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003evalor\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003edados\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003elinha\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ecoluna\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003evalor\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003em\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eMatriz\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003earrayOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eintArrayOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003eintArrayOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003em\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 2\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e    \u003cspan class=\"n\"\u003em\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e99\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003em\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 99\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"operador-invoke\"\u003eOperador \u003ccode\u003einvoke\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003eO operador \u003ccode\u003einvoke\u003c/code\u003e permite chamar um objeto como se fosse uma função:\u003c/p\u003e","title":"Operator Overloading em Kotlin: Como Funciona | Kotlin Brasil"},{"content":"O que é Delegation em Kotlin? Delegation (delegação) é um padrão de design onde um objeto repassa responsabilidades para outro. Em Kotlin, a delegação é suportada nativamente com a palavra-chave by, tanto para classes quanto para propriedades.\nEm vez de herdar de uma classe, você delega a implementação para uma instância. É o famoso princípio \u0026ldquo;composição sobre herança\u0026rdquo; que fica muito fácil de aplicar em Kotlin.\nPense na delegação como um gerente que distribui tarefas. O gerente (classe principal) não faz tudo sozinho \u0026ndash; ele delega para especialistas (objetos delegados). Quando alguém pede um relatório financeiro, o gerente repassa para o contador. O gerente sabe a quem delegar, mas não precisa saber fazer cada tarefa.\nDelegação de classe interface Repositorio { fun salvar(dados: String) fun buscar(): String } class RepositorioBanco : Repositorio { override fun salvar(dados: String) = println(\u0026#34;Salvando no banco: $dados\u0026#34;) override fun buscar() = \u0026#34;Dados do banco\u0026#34; } class RepositorioComLog(repo: Repositorio) : Repositorio by repo { override fun salvar(dados: String) { println(\u0026#34;[LOG] Operação de salvar iniciada\u0026#34;) // Delega para o repositório original, mas nao automaticamente neste override } // buscar() é delegado automaticamente } fun main() { val repo = RepositorioComLog(RepositorioBanco()) println(repo.buscar()) // Dados do banco repo.salvar(\u0026#34;teste\u0026#34;) // [LOG] Operação de salvar iniciada } O by repo faz com que todos os métodos da interface sejam delegados automaticamente. Você só sobrescreve o que quiser customizar.\nDelegação de propriedade Kotlin oferece delegates prontos pra uso:\nimport kotlin.properties.Delegates class Configuração { // Inicialização preguiçosa val conexao: String by lazy { println(\u0026#34;Conectando ao banco...\u0026#34;) \u0026#34;Conexão estabelecida\u0026#34; } // Observável — executa bloco quando muda var tema: String by Delegates.observable(\u0026#34;claro\u0026#34;) { _, antigo, novo -\u0026gt; println(\u0026#34;Tema mudou de \u0026#39;$antigo\u0026#39; para \u0026#39;$novo\u0026#39;\u0026#34;) } // Não pode ser lido antes de ser atribuído var usuario: String by Delegates.notNull() } fun main() { val config = Configuração() println(config.conexao) // \u0026#34;Conectando...\u0026#34; + \u0026#34;Conexão estabelecida\u0026#34; println(config.conexao) // \u0026#34;Conexão estabelecida\u0026#34; (já inicializou) config.tema = \u0026#34;escuro\u0026#34; // Tema mudou de \u0026#39;claro\u0026#39; para \u0026#39;escuro\u0026#39; config.usuario = \u0026#34;Karina\u0026#34; println(config.usuario) // Karina } Criando seu próprio delegate import kotlin.reflect.KProperty class FormatadoDelegate { private var valor = \u0026#34;\u0026#34; operator fun getValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;): String = valor operator fun setValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;, value: String) { valor = value.trim().lowercase() } } class Formulario { var email: String by FormatadoDelegate() } fun main() { val form = Formulario() form.email = \u0026#34; KARINA@Email.COM \u0026#34; println(form.email) // karina@email.com } Delegation em Kotlin é poderoso pra reduzir boilerplate, adicionar comportamentos transversais e manter o código organizado.\nDelegação com múltiplas interfaces Você pode delegar múltiplas interfaces para diferentes objetos, compondo comportamentos de forma flexível:\ninterface Notificador { fun notificar(mensagem: String) } interface Auditor { fun registrar(acao: String) } class NotificadorEmail : Notificador { override fun notificar(mensagem: String) { println(\u0026#34;Email enviado: $mensagem\u0026#34;) } } class AuditorLog : Auditor { override fun registrar(acao: String) { println(\u0026#34;Auditoria: $acao em ${System.currentTimeMillis()}\u0026#34;) } } class ServicoCompleto( notificador: Notificador, auditor: Auditor ) : Notificador by notificador, Auditor by auditor fun main() { val servico = ServicoCompleto(NotificadorEmail(), AuditorLog()) servico.notificar(\u0026#34;Pedido confirmado\u0026#34;) servico.registrar(\u0026#34;PEDIDO_CRIADO\u0026#34;) } Delegate para válidação de propriedades Um caso prático é criar delegates que validam valores automaticamente:\nimport kotlin.reflect.KProperty class Validado\u0026lt;T\u0026gt;( private val validacao: (T) -\u0026gt; Boolean, private val mensagemErro: String ) { private var valor: T? = null operator fun getValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;): T { return valor ?: throw IllegalStateException(\u0026#34;${property.name} nao foi inicializado\u0026#34;) } operator fun setValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;, value: T) { if (!validacao(value)) { throw IllegalArgumentException(\u0026#34;$mensagemErro: $value\u0026#34;) } valor = value } } class Cadastro { var idade: Int by Validado({ it in 0..150 }, \u0026#34;Idade invalida\u0026#34;) var nome: String by Validado({ it.isNotBlank() }, \u0026#34;Nome nao pode ser vazio\u0026#34;) } fun main() { val cadastro = Cadastro() cadastro.nome = \u0026#34;Karina\u0026#34; cadastro.idade = 28 println(\u0026#34;${cadastro.nome}, ${cadastro.idade} anos\u0026#34;) try { cadastro.idade = -5 // Lança IllegalArgumentException } catch (e: IllegalArgumentException) { println(e.message) // Idade invalida: -5 } } Delegate com Map para configurações dinâmicas Kotlin permite usar um Map como delegate, ideal para configurações carregadas de arquivos ou banco de dados:\nclass AppConfig(propriedades: Map\u0026lt;String, Any?\u0026gt;) { val nome: String by propriedades val versao: String by propriedades val debug: Boolean by propriedades } fun main() { val props = mapOf( \u0026#34;nome\u0026#34; to \u0026#34;MeuApp\u0026#34;, \u0026#34;versao\u0026#34; to \u0026#34;3.2.1\u0026#34;, \u0026#34;debug\u0026#34; to false ) val config = AppConfig(props) println(\u0026#34;${config.nome} v${config.versao} (debug=${config.debug})\u0026#34;) // MeuApp v3.2.1 (debug=false) } Casos de Uso no Mundo Real Decorator pattern: adicionar logging, cache ou métricas a uma implementação existente sem alterar o código original, como no exemplo RepositorioComLog. Injeção de dependência simplificada: delegar implementações de interfaces permite trocar comportamentos facilmente em testes. Propriedades lazy em Android: usar by lazy para inicializar views, adapters e outros componentes pesados somente quando necessário. SharedPreferences com delegates: criar delegates personalizados que leem e gravam valores automaticamente no SharedPreferences do Android. Propriedades observáveis para UI reativa: usar Delegates.observable para notificar mudanças de estado e atualizar a interface automaticamente. Boas Práticas Prefira delegação sobre herança: quando você precisa reutilizar comportamento, considere delegar para uma instância em vez de criar uma hierarquia de classes. Use by lazy para inicializações caras: propriedades que envolvem leitura de arquivo, conexão de banco ou cálculos pesados devem ser lazy. Mantenha delegates simples: cada delegate deve ter uma única responsabilidade. Use property delegates padrão antes de criar os seus. lazy, observable, notNull e vetoable cobrem a maioria dos casos. Erros Comuns Esquecer de chamar o método original no override: ao sobrescrever um método delegado, o by não repassa automaticamente. Você precisa manter uma referência ao objeto delegado se quiser chamar a implementação original. Usar by lazy com var: lazy só funciona com val, pois o valor é computado uma única vez. Para propriedades mutáveis, use Delegates.observable ou Delegates.vetoable. Ciclos de dependência em delegates: se dois delegates dependem um do outro, você pode causar um loop infinito ou StackOverflowError. Não considerar thread safety com lazy: por padrão, lazy é sincronizado (LazyThreadSafetyMode.SYNCHRONIZED). Se você tem certeza de que a propriedade será acessada por uma única thread, use lazy(LazyThreadSafetyMode.NONE) para melhor performance. Perguntas Frequentes Qual a diferença entre delegation e herança? Herança cria uma relação \u0026ldquo;é um\u0026rdquo; (is-a), enquanto delegação cria uma relação \u0026ldquo;tem um\u0026rdquo; (has-a). Delegação é mais flexível porque permite trocar o comportamento em tempo de execução e evita os problemas da herança múltipla.\nPosso delegar para uma propriedade mutável? Sim, mas cuidado. Se você usa var para o objeto delegado, trocar a referência não atualiza a delegação, pois o by captura a referência no momento da construção.\nO que é Delegates.vetoable? É similar ao observable, mas permite rejeitar a mudança de valor. A lambda retorna Boolean: se retornar false, o valor não é atualizado.\nDelegação de classe funciona com classes abstratas? Não. A delegação com by só funciona com interfaces. Você não pode usar by para delegar a implementação de uma classe abstrata ou concreta.\n","permalink":"https://kotlin.dev.br/glossario/delegation/","summary":"\u003ch2 id=\"o-que-é-delegation-em-kotlin\"\u003eO que é Delegation em Kotlin?\u003c/h2\u003e\n\u003cp\u003eDelegation (delegação) é um padrão de design onde um objeto repassa responsabilidades para outro. Em Kotlin, a delegação é suportada \u003cstrong\u003enativamente\u003c/strong\u003e com a palavra-chave \u003ccode\u003eby\u003c/code\u003e, tanto para classes quanto para propriedades.\u003c/p\u003e\n\u003cp\u003eEm vez de herdar de uma classe, você delega a implementação para uma instância. É o famoso princípio \u0026ldquo;composição sobre herança\u0026rdquo; que fica muito fácil de aplicar em Kotlin.\u003c/p\u003e\n\u003cp\u003ePense na delegação como um gerente que distribui tarefas. O gerente (classe principal) não faz tudo sozinho \u0026ndash; ele delega para especialistas (objetos delegados). Quando alguém pede um relatório financeiro, o gerente repassa para o contador. O gerente sabe a quem delegar, mas não precisa saber fazer cada tarefa.\u003c/p\u003e","title":"Delegation em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que são Generics em Kotlin? Generics permitem criar classes, interfaces e funções que funcionam com qualquer tipo, mantendo a segurança de tipos em tempo de compilação. Em vez de escrever código específico para Int, String ou qualquer outro tipo, você escreve uma vez e reutiliza com qualquer um deles.\nClasse genérica class Caixa\u0026lt;T\u0026gt;(val conteudo: T) { fun abrir(): T { println(\u0026#34;Abrindo a caixa...\u0026#34;) return conteudo } } fun main() { val caixaDeTexto = Caixa(\u0026#34;Presente surpresa\u0026#34;) val caixaDeNumero = Caixa(42) println(caixaDeTexto.abrir()) // Presente surpresa println(caixaDeNumero.abrir()) // 42 } O T é um parâmetro de tipo — pode ser qualquer coisa. O compilador garante que você não misture os tipos.\nFunção genérica fun \u0026lt;T\u0026gt; trocar(par: Pair\u0026lt;T, T\u0026gt;): Pair\u0026lt;T, T\u0026gt; { return Pair(par.second, par.first) } fun main() { val original = Pair(\u0026#34;Kotlin\u0026#34;, \u0026#34;Java\u0026#34;) val trocado = trocar(original) println(trocado) // (Java, Kotlin) } Restrições de tipo Você pode restringir quais tipos são aceitos usando where ou ::\nfun \u0026lt;T : Comparable\u0026lt;T\u0026gt;\u0026gt; maior(a: T, b: T): T { return if (a \u0026gt; b) a else b } fun main() { println(maior(10, 20)) // 20 println(maior(\u0026#34;Kotlin\u0026#34;, \u0026#34;Java\u0026#34;)) // Kotlin } Quando precisa de múltiplas restrições, use a cláusula where:\nfun \u0026lt;T\u0026gt; processar(item: T) where T : Comparable\u0026lt;T\u0026gt;, T : CharSequence { println(\u0026#34;Tamanho: ${item.length}, Valor: $item\u0026#34;) } fun main() { processar(\u0026#34;Kotlin\u0026#34;) // Tamanho: 6, Valor: Kotlin // processar(42) // Erro: Int nao implementa CharSequence } Variância: in e out Kotlin tem um sistema de variância mais explícito que Java:\n// out = produtor (covariant) — só retorna T interface Fonte\u0026lt;out T\u0026gt; { fun obter(): T } // in = consumidor (contravariant) — só recebe T interface Destino\u0026lt;in T\u0026gt; { fun enviar(item: T) } class FonteDeString : Fonte\u0026lt;String\u0026gt; { override fun obter() = \u0026#34;Kotlin Brasil\u0026#34; } fun main() { val fonte: Fonte\u0026lt;Any\u0026gt; = FonteDeString() // Funciona por causa do out println(fonte.obter()) } out T significa que T só aparece como retorno (posição de saída) in T significa que T só aparece como parâmetro (posição de entrada) Projeção de tipo (star projection) Quando você não se importa com o tipo genérico, use *:\nfun imprimirItens(lista: List\u0026lt;*\u0026gt;) { lista.forEach { println(it) } } Reified type parameters Em Kotlin, os tipos genéricos são apagados em tempo de execução (type erasure). Porém, com funções inline e o modificador reified, você pode acessar o tipo genérico em runtime:\ninline fun \u0026lt;reified T\u0026gt; verificarTipo(valor: Any): Boolean { return valor is T } fun main() { println(verificarTipo\u0026lt;String\u0026gt;(\u0026#34;Kotlin\u0026#34;)) // true println(verificarTipo\u0026lt;Int\u0026gt;(\u0026#34;Kotlin\u0026#34;)) // false } Isso é muito usado em frameworks para deserialização, injeção de dependência e navegação entre telas no Android.\nGenerics em interfaces e herança Generics se combinam naturalmente com interfaces para criar contratos flexíveis:\ninterface Repositorio\u0026lt;T\u0026gt; { fun buscarPorId(id: Int): T? fun salvar(item: T) fun listarTodos(): List\u0026lt;T\u0026gt; } data class Produto(val id: Int, val nome: String, val preco: Double) class ProdutoRepositorio : Repositorio\u0026lt;Produto\u0026gt; { private val itens = mutableListOf\u0026lt;Produto\u0026gt;() override fun buscarPorId(id: Int) = itens.find { it.id == id } override fun salvar(item: Produto) { itens.add(item) } override fun listarTodos() = itens.toList() } fun main() { val repo = ProdutoRepositorio() repo.salvar(Produto(1, \u0026#34;Notebook\u0026#34;, 3500.0)) repo.salvar(Produto(2, \u0026#34;Mouse\u0026#34;, 89.90)) println(repo.listarTodos()) } Casos de Uso no Mundo Real Repositórios genéricos: criar uma interface Repositorio\u0026lt;T\u0026gt; que define operações CRUD e implementar para cada entidade do sistema, eliminando duplicação de código de acesso a dados. Respostas de API padronizadas: usar uma classe ApiResponse\u0026lt;T\u0026gt; que encapsula sucesso, erro e loading, permitindo que qualquer endpoint retorne o mesmo formato independente do tipo de dado. Adapters no Android: RecyclerView.Adapter\u0026lt;VH\u0026gt; usa generics para tipar o ViewHolder, e você pode criar adapters genéricos que funcionam com diferentes tipos de itens de lista. Injeção de dependência: frameworks como Koin e Hilt usam reified type parameters para resolver dependências pelo tipo sem precisar passar a classe como parâmetro explícito. Boas Práticas Use nomes de parâmetros de tipo descritivos quando o contexto exigir: T para tipo genérico, K e V para chave e valor, E para elementos de coleção, R para tipo de retorno. Prefira out em interfaces que apenas produzem valores e in em interfaces que apenas consomem. Isso torna a API mais flexível para os consumidores. Utilize restrições de tipo (T : AlgumaInterface) sempre que possível para evitar casts desnecessários e manter a segurança de tipos. Combine inline com reified quando precisar acessar o tipo genérico em runtime, em vez de passar KClass\u0026lt;T\u0026gt; como parâmetro. Evite star projection (*) quando você pode ser mais específico sobre o tipo, pois * limita as operações disponíveis. Erros Comuns Tentar fazer is T sem reified: devido ao type erasure, verificar o tipo genérico em runtime exige que a função seja inline e o parâmetro de tipo seja reified. Confundir in e out: usar out quando o tipo aparece em posição de entrada (parâmetro) causa erro de compilação. Lembre: out = saída (retorno), in = entrada (parâmetro). Criar hierarquias genéricas excessivamente complexas: aninhar múltiplos parâmetros de tipo como Classe\u0026lt;A\u0026lt;B\u0026lt;C\u0026gt;\u0026gt;\u0026gt; dificulta a leitura. Simplifique com typealias ou quebre em interfaces menores. Esquecer que List\u0026lt;Any\u0026gt; não é supertipo de List\u0026lt;String\u0026gt; sem variância: em Kotlin, List já é declarada como List\u0026lt;out E\u0026gt;, então funciona. Mas para suas próprias classes, você precisa declarar a variância explicitamente. Usar casts genéricos não verificados: lista as List\u0026lt;String\u0026gt; gera um warning de unchecked cast porque o tipo genérico é apagado em runtime. Use filterIsInstance\u0026lt;String\u0026gt;() quando possível. Perguntas Frequentes Qual a diferença entre generics em Kotlin e em Java? Kotlin usa in e out para variância no local de declaração (declaration-site variance), enquanto Java usa wildcards ? extends e ? super no local de uso (use-site variance). Kotlin também suporta reified type parameters, que não existem em Java.\nO que é type erasure e como afeta generics? Type erasure significa que os tipos genéricos são apagados em tempo de execução. Um List\u0026lt;String\u0026gt; e um List\u0026lt;Int\u0026gt; são indistinguíveis na JVM. O modificador reified em funções inline é a solução do Kotlin para contornar essa limitação.\nPosso ter múltiplos parâmetros de tipo? Sim. Você pode declarar quantos precisar: class Mapa\u0026lt;K, V\u0026gt;, fun \u0026lt;A, B\u0026gt; converter(valor: A, transformador: (A) -\u0026gt; B): B. Cada parâmetro pode ter suas próprias restrições.\nQuando devo usar star projection? Use * quando você precisa trabalhar com um tipo genérico mas não se importa com o parâmetro de tipo específico, como em funções que apenas imprimem ou verificam se uma coleção está vazia.\nTermos Relacionados Interface — contratos que frequentemente utilizam generics para definir APIs flexíveis Inline — modificador necessário para usar reified type parameters Fun — funções genéricas são declaradas com fun seguido de parâmetros de tipo Lambda — frequentemente usada com funções genéricas como map\u0026lt;T, R\u0026gt; Generics são essenciais para escrever código reutilizável e type-safe. A biblioteca padrão do Kotlin usa generics em praticamente tudo: listas, maps, flows e muito mais.\n","permalink":"https://kotlin.dev.br/glossario/generics/","summary":"\u003ch2 id=\"o-que-são-generics-em-kotlin\"\u003eO que são Generics em Kotlin?\u003c/h2\u003e\n\u003cp\u003eGenerics permitem criar \u003cstrong\u003eclasses, interfaces e funções que funcionam com qualquer tipo\u003c/strong\u003e, mantendo a segurança de tipos em tempo de compilação. Em vez de escrever código específico para \u003ccode\u003eInt\u003c/code\u003e, \u003ccode\u003eString\u003c/code\u003e ou qualquer outro tipo, você escreve uma vez e reutiliza com qualquer um deles.\u003c/p\u003e\n\u003ch3 id=\"classe-genérica\"\u003eClasse genérica\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eCaixa\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eT\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;(\u003c/span\u003e\u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003econteudo\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eT\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003eabrir\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e \u003cspan class=\"n\"\u003eT\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Abrindo a caixa...\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003econteudo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003ecaixaDeTexto\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eCaixa\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Presente surpresa\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003ecaixaDeNumero\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eCaixa\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e42\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecaixaDeTexto\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eabrir\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Presente surpresa\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecaixaDeNumero\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eabrir\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 42\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eO \u003ccode\u003eT\u003c/code\u003e é um parâmetro de tipo — pode ser qualquer coisa. O compilador garante que você não misture os tipos.\u003c/p\u003e","title":"Generics em Kotlin: O que São e Como Funcionam | Kotlin Brasil"},{"content":"O que é abstract em Kotlin? O modificador abstract em Kotlin marca classes e membros que não possuem implementação completa e precisam ser implementados por subclasses. Uma classe abstrata não pode ser instanciada diretamente — ela serve como base para outras classes.\nDiferente de interfaces, classes abstratas podem ter construtores, estado interno e métodos concretos junto com os abstratos.\nPense em uma classe abstrata como uma planta de uma casa: ela define a estrutura geral (quantos quartos, onde fica a cozinha), mas cada construtor vai decidir os detalhes finais (tipo de piso, cor das paredes). Voce não constroi a planta em si, mas toda casa concreta segue aquela planta como base.\nSintaxe básica abstract class Forma(val cor: String) { abstract fun area(): Double abstract fun perimetro(): Double fun descricao(): String { return \u0026#34;Forma $cor com area ${area()}\u0026#34; } } class Circulo(cor: String, val raio: Double) : Forma(cor) { override fun area() = Math.PI * raio * raio override fun perimetro() = 2 * Math.PI * raio } class Retangulo(cor: String, val largura: Double, val altura: Double) : Forma(cor) { override fun area() = largura * altura override fun perimetro() = 2 * (largura + altura) } fun main() { val circulo = Circulo(\u0026#34;vermelho\u0026#34;, 5.0) println(circulo.descricao()) // Forma vermelho com area 78.53... val retangulo = Retangulo(\u0026#34;azul\u0026#34;, 4.0, 6.0) println(retangulo.descricao()) // Forma azul com area 24.0 } Propriedades abstratas Alem de funções, propriedades também podem ser abstratas:\nabstract class Veiculo { abstract val velocidadeMaxima: Int abstract val tipo: String fun info() = \u0026#34;$tipo - Velocidade max: $velocidadeMaxima km/h\u0026#34; } class Carro : Veiculo() { override val velocidadeMaxima = 200 override val tipo = \u0026#34;Carro\u0026#34; } class Bicicleta : Veiculo() { override val velocidadeMaxima = 40 override val tipo = \u0026#34;Bicicleta\u0026#34; } Classes abstratas não precisam de open Classes abstratas já sao implicitamente open, entao subclasses podem herda-las sem precisar marcar nada extra. Membros abstratos também sao automaticamente open.\nAbstract class vs Interface Aspecto Abstract Class Interface Construtor Sim Nao Estado (campos) Sim Nao (só propriedades) Heranca multipla Nao Sim Metodos concretos Sim Sim Use classes abstratas quando suas subclasses compartilham estado e comportamento base. Para contratos puros sem estado, prefira interfaces.\nSistema de notificacoes com classe abstrata Um cenário real e construir um sistema de notificacoes onde cada tipo de notificação compartilha lógica comum mas tem seu próprio método de envio:\nabstract class Notificacao(val destinatario: String) { val criadoEm: Long = System.currentTimeMillis() abstract fun enviar(mensagem: String): Boolean abstract fun validarDestinatario(): Boolean fun enviarComValidacao(mensagem: String): Boolean { if (!validarDestinatario()) { println(\u0026#34;Destinatario invalido: $destinatario\u0026#34;) return false } return enviar(mensagem) } } class NotificacaoEmail(destinatario: String) : Notificacao(destinatario) { override fun enviar(mensagem: String): Boolean { println(\u0026#34;Enviando email para $destinatario: $mensagem\u0026#34;) return true } override fun validarDestinatario(): Boolean { return destinatario.contains(\u0026#34;@\u0026#34;) \u0026amp;\u0026amp; destinatario.contains(\u0026#34;.\u0026#34;) } } class NotificacaoSms(destinatario: String) : Notificacao(destinatario) { override fun enviar(mensagem: String): Boolean { println(\u0026#34;Enviando SMS para $destinatario: $mensagem\u0026#34;) return true } override fun validarDestinatario(): Boolean { return destinatario.length \u0026gt;= 10 \u0026amp;\u0026amp; destinatario.all { it.isDigit() || it == \u0026#39;+\u0026#39; } } } Repositorio generico com classe abstrata Outro uso comum e criar uma camada de acesso a dados reutilizavel:\nabstract class Repositorio\u0026lt;T\u0026gt; { protected val itens = mutableListOf\u0026lt;T\u0026gt;() abstract fun buscarPorId(id: String): T? fun salvar(item: T) { itens.add(item) println(\u0026#34;Item salvo. Total: ${itens.size}\u0026#34;) } fun listarTodos(): List\u0026lt;T\u0026gt; = itens.toList() fun removerTodos() { itens.clear() } } data class Usuario(val id: String, val nome: String, val email: String) class UsuarioRepositorio : Repositorio\u0026lt;Usuario\u0026gt;() { override fun buscarPorId(id: String): Usuario? { return itens.find { it.id == id } } } Casos de Uso no Mundo Real Frameworks de UI: classes abstratas definem o ciclo de vida de componentes visuais (como Activity e Fragment no Android), onde cada tela implementa seus próprios métodos mas herda comportamento padrão. Camadas de persistencia: repositórios abstratos padronizam operações de CRUD, enquanto implementacoes concretas se conectam a bancos de dados específicos como Room ou Exposed. Processamento de dados: pipelines de ETL usam classes abstratas para definir etapas comuns (ler, transformar, gravar), enquanto cada fonte de dados implementa a lógica específica. Testes: classes abstratas de teste definem cenários comuns que sao reutilizados por testes concretos de diferentes implementacoes. Boas Praticas Use classes abstratas quando subclasses compartilham estado (propriedades com valor) ou lógica de inicialização via construtor. Prefira interfaces quando você precisa apenas de um contrato sem estado. Mantenha classes abstratas focadas em um único proposito. Evite criar \u0026ldquo;super classes\u0026rdquo; que tentam fazer tudo. Combine classes abstratas com generics para criar bases reutilizaveis e type-safe. Documente claramente o que cada método abstrato deve fazer, para que quem implementa a subclasse saiba o que e esperado. Erros Comuns Tentar instanciar uma classe abstrata diretamente: val forma = Forma(\u0026quot;azul\u0026quot;) causa erro de compilação. Voce deve criar uma subclasse concreta e instancia-la. Esquecer de implementar todos os membros abstratos: se a subclasse não e abstrata, ela precisa implementar todos os métodos e propriedades abstratos. O compilador aponta o erro, mas pode confundir iniciantes. Usar abstract quando interface seria suficiente: se a classe base não tem estado nem construtor, uma interface e mais flexivel porque permite heranca multipla. Confundir abstract com open: open permite que uma classe seja herdada mas fornece implementação completa. abstract exige que subclasses fornecam a implementação. Perguntas Frequentes Posso ter um construtor em uma classe abstrata? Sim. Diferente de interfaces, classes abstratas suportam construtores com parametros. As subclasses devem chamar o construtor da classe abstrata ao herda-la, como em class Circulo(cor: String) : Forma(cor).\nUma classe abstrata pode implementar uma interface? Sim. Uma classe abstrata pode implementar uma ou mais interfaces e até deixar alguns métodos da interface sem implementação para que as subclasses completem.\nPosso ter métodos concretos em uma classe abstrata? Sim, e esse e um dos grandes diferenciais. Voce pode misturar métodos abstratos (sem corpo) com métodos concretos (com implementação), permitindo que subclasses reutilizem lógica comum.\nQuando devo usar sealed class em vez de abstract class? Use sealed class quando você quer restringir quais subclasses podem existir. Com abstract class, qualquer modulo pode criar uma subclasse. Com sealed class, todas as subclasses devem estar no mesmo pacote, o que permite uso seguro com when.\n","permalink":"https://kotlin.dev.br/glossario/abstract/","summary":"\u003ch2 id=\"o-que-é-abstract-em-kotlin\"\u003eO que é \u003ccode\u003eabstract\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO modificador \u003ccode\u003eabstract\u003c/code\u003e em Kotlin marca classes e membros que \u003cstrong\u003enão possuem implementação completa\u003c/strong\u003e e precisam ser implementados por subclasses. Uma classe abstrata não pode ser instanciada diretamente — ela serve como base para outras classes.\u003c/p\u003e\n\u003cp\u003eDiferente de interfaces, classes abstratas podem ter construtores, estado interno e métodos concretos junto com os abstratos.\u003c/p\u003e\n\u003cp\u003ePense em uma classe abstrata como uma planta de uma casa: ela define a estrutura geral (quantos quartos, onde fica a cozinha), mas cada construtor vai decidir os detalhes finais (tipo de piso, cor das paredes). Voce não constroi a planta em si, mas toda casa concreta segue aquela planta como base.\u003c/p\u003e","title":"Abstract em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"Sobre a vagaA Getnet busca uma pessoa Desenvolvedora Backend Sênior para atuar presencialmente em Porto Alegre ou São Paulo, com foco em Kotlin, Java e Spring Framework.\nResponsabilidadesDesenvolver e manter serviços backend usando Kotlin, Java e Spring Framework.Trabalhar com integrações, APIs e documentação com Swagger.Atuar com bancos de dados MongoDB e mensageria com RabbitMQ.Apoiar práticas de DevOps, versionamento com Git e infraestrutura como código com Terraform.Colaborar em ambientes cloud usando AWS e Azure.RequisitosExperiência sênior em desenvolvimento backend.Conhecimento sólido em Kotlin, Java e Spring Framework.Experiência com MongoDB, RabbitMQ, Swagger e Git.Vivência com AWS, Azure, DevOps e Terraform.Disponibilidade para trabalho presencial em Porto Alegre ou São Paulo. ","permalink":"https://kotlin.dev.br/vagas/6mrqssgjhd7ae50s-getnet-desenvolvedor-backend-senior-kotlin-e-java/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Getnet busca uma pessoa Desenvolvedora Backend Sênior para atuar presencialmente em Porto Alegre ou São Paulo, com foco em Kotlin, Java e Spring Framework.\u003c/p\u003e\u003ch3\u003eResponsabilidades\u003c/h3\u003e\u003cul\u003e\u003cli\u003eDesenvolver e manter serviços backend usando Kotlin, Java e Spring Framework.\u003c/li\u003e\u003cli\u003eTrabalhar com integrações, APIs e documentação com Swagger.\u003c/li\u003e\u003cli\u003eAtuar com bancos de dados MongoDB e mensageria com RabbitMQ.\u003c/li\u003e\u003cli\u003eApoiar práticas de DevOps, versionamento com Git e infraestrutura como código com Terraform.\u003c/li\u003e\u003cli\u003eColaborar em ambientes cloud usando AWS e Azure.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência sênior em desenvolvimento backend.\u003c/li\u003e\u003cli\u003eConhecimento sólido em Kotlin, Java e Spring Framework.\u003c/li\u003e\u003cli\u003eExperiência com MongoDB, RabbitMQ, Swagger e Git.\u003c/li\u003e\u003cli\u003eVivência com AWS, Azure, DevOps e Terraform.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho presencial em Porto Alegre ou São Paulo.\u003c/li\u003e\u003c/ul\u003e","title":"Desenvolvedor Backend Sênior Kotlin e Java"},{"content":"O que é Interface em Kotlin? Uma interface em Kotlin define um contrato que classes devem seguir. Ela declara quais funções e propriedades uma classe precisa ter, mas sem obrigar uma implementação específica. Diferente de classes abstratas, uma classe pode implementar várias interfaces.\nSintaxe básica interface Autenticavel { fun autenticar(senha: String): Boolean } class Usuario(val nome: String, private val senhaHash: String) : Autenticavel { override fun autenticar(senha: String): Boolean { return senha == senhaHash } } fun main() { val user = Usuario(\u0026#34;Karina\u0026#34;, \u0026#34;abc123\u0026#34;) println(user.autenticar(\u0026#34;abc123\u0026#34;)) // true println(user.autenticar(\u0026#34;errada\u0026#34;)) // false } Métodos com implementação padrão Em Kotlin, interfaces podem ter métodos com corpo — os famosos default methods:\ninterface Logavel { val tag: String get() = this::class.simpleName ?: \u0026#34;Desconhecido\u0026#34; fun log(mensagem: String) { println(\u0026#34;[$tag] $mensagem\u0026#34;) } } class Servico : Logavel fun main() { val servico = Servico() servico.log(\u0026#34;Iniciando processamento\u0026#34;) // [Servico] Iniciando processamento } Múltiplas interfaces interface Imprimivel { fun imprimir() } interface Exportavel { fun exportar(): String } class Relatorio(val titulo: String) : Imprimivel, Exportavel { override fun imprimir() { println(\u0026#34;Imprimindo: $titulo\u0026#34;) } override fun exportar(): String { return \u0026#34;PDF: $titulo\u0026#34; } } fun main() { val relatorio = Relatorio(\u0026#34;Vendas Q1\u0026#34;) relatorio.imprimir() println(relatorio.exportar()) } Resolvendo conflitos Quando duas interfaces têm o mesmo método com implementação padrão, você precisa resolver o conflito manualmente:\ninterface A { fun saudacao() = \u0026#34;Olá de A\u0026#34; } interface B { fun saudacao() = \u0026#34;Olá de B\u0026#34; } class C : A, B { override fun saudacao(): String { return \u0026#34;${super\u0026lt;A\u0026gt;.saudacao()} e ${super\u0026lt;B\u0026gt;.saudacao()}\u0026#34; } } Quando usar interface vs abstract class? Use interface quando quiser definir um contrato que múltiplas classes podem adotar. Use abstract class quando precisar de estado compartilhado (campos com valores) ou construtores. Interfaces são mais flexíveis e promovem um design mais desacoplado.\nInterface com propriedades abstratas Interfaces podem declarar propriedades que as classes implementadoras devem fornecer:\ninterface Identificavel { val id: String val tipo: String get() = \u0026#34;genérico\u0026#34; // Propriedade com valor padrao } interface Auditavel { val criadoEm: Long val atualizadoEm: Long } data class Documento( override val id: String, val titulo: String, override val criadoEm: Long, override val atualizadoEm: Long ) : Identificavel, Auditavel { override val tipo: String get() = \u0026#34;documento\u0026#34; } fun main() { val doc = Documento(\u0026#34;doc-001\u0026#34;, \u0026#34;Contrato\u0026#34;, 1700000000, 1700100000) println(\u0026#34;${doc.tipo}: ${doc.titulo} (ID: ${doc.id})\u0026#34;) // documento: Contrato (ID: doc-001) } Interface como tipo para injeção de dependência Um dos usos mais poderosos de interfaces é permitir a substituição de implementações, fundamental para testes e arquiteturas desacopladas:\ninterface NotificacaoService { fun enviar(destinatario: String, mensagem: String): Boolean } class EmailService : NotificacaoService { override fun enviar(destinatario: String, mensagem: String): Boolean { println(\u0026#34;Enviando email para $destinatario: $mensagem\u0026#34;) return true } } class SmsService : NotificacaoService { override fun enviar(destinatario: String, mensagem: String): Boolean { println(\u0026#34;Enviando SMS para $destinatario: $mensagem\u0026#34;) return true } } // Em testes, voce pode criar um fake facilmente class FakeNotificacaoService : NotificacaoService { val mensagensEnviadas = mutableListOf\u0026lt;Pair\u0026lt;String, String\u0026gt;\u0026gt;() override fun enviar(destinatario: String, mensagem: String): Boolean { mensagensEnviadas.add(destinatario to mensagem) return true } } class PedidoService(private val notificacao: NotificacaoService) { fun finalizarPedido(clienteEmail: String) { // ... logica do pedido notificacao.enviar(clienteEmail, \u0026#34;Seu pedido foi confirmado!\u0026#34;) } } Sealed interfaces A partir do Kotlin 1.5, você pode usar sealed interfaces para restringir quais classes podem implementar uma interface:\nsealed interface Resultado { data class Sucesso(val dados: String) : Resultado data class Erro(val mensagem: String) : Resultado data object Carregando : Resultado } fun processar(resultado: Resultado) { when (resultado) { is Resultado.Sucesso -\u0026gt; println(\u0026#34;Dados: ${resultado.dados}\u0026#34;) is Resultado.Erro -\u0026gt; println(\u0026#34;Erro: ${resultado.mensagem}\u0026#34;) Resultado.Carregando -\u0026gt; println(\u0026#34;Carregando...\u0026#34;) } } O when é exaustivo automaticamente para sealed interfaces, dispensando o ramo else.\nCasos de Uso no Mundo Real Camada de repositório: definir uma interface UsuarioRepository com operações como buscarPorId, salvar e deletar, permitindo trocar a implementação entre banco de dados real e repositório em memória para testes. Strategy pattern em regras de negócio: criar uma interface CalculoFrete com diferentes implementações para Correios, transportadora e retirada, injetando a estratégia correta conforme a escolha do cliente. Plugins e extensibilidade: sistemas de plugins usam interfaces para definir contratos que módulos externos devem seguir, permitindo adicionar funcionalidades sem modificar o código principal. Tratamento de estado com sealed interface: modelar estados de tela no Android (Loading, Success, Error) como uma sealed interface, garantindo que o when cubra todos os estados possíveis. Boas Práticas Prefira interfaces pequenas e focadas (Interface Segregation Principle). Uma interface com muitos métodos força implementadores a lidar com funcionalidades que podem não ser relevantes. Use implementações padrão com moderação. Elas são úteis para métodos auxiliares, mas não devem conter lógica de negócio complexa que seria melhor em uma classe abstrata. Nomeie interfaces pelo comportamento que descrevem, não pela implementação: Serializavel, Persistivel, Autenticavel comunicam intenção melhor que SerializadorImpl ou BancoDeDados. Programe para a interface, não para a implementação. Declare variáveis e parâmetros usando o tipo da interface sempre que possível. Use sealed interfaces quando o conjunto de implementações é fechado e conhecido, permitindo when exaustivo e maior segurança em tempo de compilação. Erros Comuns Criar interfaces com um único implementador sem justificativa: se a interface existe apenas por existir e nunca será reimplementada, ela adiciona complexidade sem benefício. Crie interfaces quando houver necessidade real de abstração. Colocar estado mutável em interfaces: interfaces não devem ter campos var com backing field. Se precisa de estado compartilhado, use uma classe abstrata. Esquecer o override ao implementar métodos da interface: diferente de Java, Kotlin exige a palavra-chave override explicitamente, o que previne erros acidentais. Não resolver conflitos de nomes entre interfaces: quando duas interfaces têm métodos com o mesmo nome e implementação padrão, a classe deve resolver explicitamente com super\u0026lt;Interface\u0026gt;.método(). Usar interface quando abstract class seria mais apropriada: se as implementações compartilham estado (propriedades com backing field) ou lógica de construtor, uma classe abstrata é a escolha mais adequada. Perguntas Frequentes Interfaces em Kotlin podem ter construtores? Não. Interfaces não podem ter construtores. Se você precisa de parâmetros de inicialização, use uma classe abstrata.\nQual a diferença entre interface em Kotlin e em Java? Em Kotlin, interfaces podem ter propriedades (sem backing field), implementações padrão de métodos e participar de sealed hierarchies. Em Java, default methods existem desde o Java 8, mas propriedades em interfaces não são suportadas.\nPosso usar delegação com interfaces? Sim. Kotlin suporta delegação de interface com a palavra-chave by: class MeuServico(servico: NotificacaoService) : NotificacaoService by servico. Isso delega todas as chamadas de interface para o objeto fornecido.\nQuando usar sealed interface vs sealed class? Use sealed interface quando as implementações não precisam compartilhar estado (propriedades com backing field) e quando deseja que uma classe implemente múltiplas sealed hierarchies. Sealed class é melhor quando há estado e lógica compartilhados.\nTermos Relacionados Fun — funções declaradas em interfaces são implementadas usando fun e override Generics — interfaces genéricas como Comparable\u0026lt;T\u0026gt; e Iterable\u0026lt;T\u0026gt; definem contratos flexíveis Lambda — interfaces funcionais (SAM) podem ser substituídas por lambdas em Kotlin Higher-Order Function — interfaces com um único método abstrato podem ser usadas como tipos de função ","permalink":"https://kotlin.dev.br/glossario/interface/","summary":"\u003ch2 id=\"o-que-é-interface-em-kotlin\"\u003eO que é Interface em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUma \u003ccode\u003einterface\u003c/code\u003e em Kotlin define um \u003cstrong\u003econtrato\u003c/strong\u003e que classes devem seguir. Ela declara quais funções e propriedades uma classe precisa ter, mas sem obrigar uma implementação específica. Diferente de classes abstratas, uma classe pode implementar \u003cstrong\u003evárias interfaces\u003c/strong\u003e.\u003c/p\u003e\n\u003ch3 id=\"sintaxe-básica\"\u003eSintaxe básica\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003einterface\u003c/span\u003e \u003cspan class=\"nc\"\u003eAutenticavel\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003eautenticar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esenha\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e \u003cspan class=\"n\"\u003eBoolean\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eUsuario\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003enome\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"k\"\u003eprivate\u003c/span\u003e \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003esenhaHash\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eAutenticavel\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eoverride\u003c/span\u003e \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003eautenticar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esenha\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e \u003cspan class=\"n\"\u003eBoolean\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003esenha\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003esenhaHash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003euser\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eUsuario\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Karina\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;abc123\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003euser\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eautenticar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;abc123\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"c1\"\u003e// true\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003euser\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eautenticar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;errada\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"c1\"\u003e// false\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"métodos-com-implementação-padrão\"\u003eMétodos com implementação padrão\u003c/h3\u003e\n\u003cp\u003eEm Kotlin, interfaces podem ter métodos com corpo — os famosos \u003cstrong\u003edefault methods\u003c/strong\u003e:\u003c/p\u003e","title":"Interface em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Annotation em Kotlin? Annotations (anotacoes) sao metadados que você adiciona ao código para fornecer informações extras ao compilador, a ferramentas de build ou a frameworks em tempo de execução. Elas não mudam o comportamento do código diretamente, mas servem como instrucoes pra quem processa o código.\nSe você já usou @Override em Java ou @Composable no Jetpack Compose, já usou annotations.\nPense em annotations como etiquetas coladas em um produto: a etiqueta não muda o produto em si, mas informa quem o manipula (o caixa, o estoquista, o transportador) sobre como trata-lo. Da mesma forma, annotations informam o compilador, frameworks e ferramentas sobre como processar determinado trecho de código.\nUsando annotations existentes class Animal { @Deprecated(\u0026#34;Use falar() no lugar\u0026#34;, ReplaceWith(\u0026#34;falar()\u0026#34;)) fun emitirSom() { println(\u0026#34;Som generico\u0026#34;) } fun falar() { println(\u0026#34;Som do animal\u0026#34;) } } fun main() { val animal = Animal() animal.emitirSom() // Aviso: Deprecated animal.falar() } Annotations comuns do Kotlin:\n@Deprecated \u0026ndash; marca algo como obsoleto @Suppress \u0026ndash; suprime avisos do compilador @JvmStatic \u0026ndash; gera método estático pra interop com Java @Throws \u0026ndash; declara exceções pra interop com Java Criando suas proprias annotations @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) annotation class LogExecucao(val nivel: String = \u0026#34;INFO\u0026#34;) @LogExecucao(nivel = \u0026#34;DEBUG\u0026#34;) fun processarDados() { println(\u0026#34;Processando...\u0026#34;) } Os meta-annotations controlam o comportamento:\n@Target \u0026ndash; onde pode ser aplicada (classe, função, propriedade, etc.) @Retention \u0026ndash; se fica disponivel em runtime, só no binario, ou só no código fonte Exemplo prático: validacao @Target(AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.RUNTIME) annotation class CampoObrigatorio data class Formulario( @CampoObrigatorio val nome: String, @CampoObrigatorio val email: String, val telefone: String = \u0026#34;\u0026#34; ) Depois, usando reflexao, da pra verificar quais campos tem @CampoObrigatorio e validar automaticamente.\nAnnotations com use-site targets Em Kotlin, como propriedades geram campo, getter e setter, as vezes e necessário especificar onde a annotation vai:\nclass Config( @field:NotNull val nome: String, @get:JsonProperty(\u0026#34;valor_padrao\u0026#34;) val valorPadrao: String ) Annotations sao fundamentais no ecossistema Kotlin, especialmente com Spring Boot, Ktor, Room e outros frameworks que dependem de metadados para funcionar.\nProcessando annotations com reflexao Um uso poderoso de annotations e processa-las em tempo de execução para criar comportamentos dinâmicos. Veja como validar campos anotados automaticamente:\nimport kotlin.reflect.full.declaredMemberProperties import kotlin.reflect.full.findAnnotation @Target(AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.RUNTIME) annotation class Obrigatorio(val mensagem: String = \u0026#34;Campo obrigatorio\u0026#34;) @Target(AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.RUNTIME) annotation class TamanhoMaximo(val valor: Int) data class CadastroUsuario( @Obrigatorio val nome: String, @Obrigatorio val email: String, @TamanhoMaximo(11) val cpf: String, val apelido: String = \u0026#34;\u0026#34; ) fun \u0026lt;T : Any\u0026gt; validar(obj: T): List\u0026lt;String\u0026gt; { val erros = mutableListOf\u0026lt;String\u0026gt;() for (prop in obj::class.declaredMemberProperties) { val valor = prop.getter.call(obj)?.toString() ?: \u0026#34;\u0026#34; prop.findAnnotation\u0026lt;Obrigatorio\u0026gt;()?.let { if (valor.isBlank()) erros.add(it.mensagem) } prop.findAnnotation\u0026lt;TamanhoMaximo\u0026gt;()?.let { if (valor.length \u0026gt; it.valor) { erros.add(\u0026#34;${prop.name} excede ${it.valor} caracteres\u0026#34;) } } } return erros } Annotations para serialização e APIs Annotations sao amplamente usadas com bibliotecas de serialização como kotlinx.serialization:\nimport kotlinx.serialization.Serializable import kotlinx.serialization.SerialName import kotlinx.serialization.json.Json @Serializable data class ProdutoApi( @SerialName(\u0026#34;product_id\u0026#34;) val id: Int, @SerialName(\u0026#34;product_name\u0026#34;) val nome: String, @SerialName(\u0026#34;unit_price\u0026#34;) val precoUnitario: Double ) fun main() { val json = \u0026#34;\u0026#34;\u0026#34;{\u0026#34;product_id\u0026#34;: 1, \u0026#34;product_name\u0026#34;: \u0026#34;Teclado\u0026#34;, \u0026#34;unit_price\u0026#34;: 299.90}\u0026#34;\u0026#34;\u0026#34; val produto = Json.decodeFromString\u0026lt;ProdutoApi\u0026gt;(json) println(produto.nome) // Teclado } Casos de Uso no Mundo Real Injecao de dependência: frameworks como Koin e Hilt usam annotations como @Inject, @Module e @Singleton para configurar o grafo de dependências automaticamente. Mapeamento de banco de dados: Room usa @Entity, @PrimaryKey e @ColumnInfo para mapear data classes a tabelas do banco. Endpoints de API: no Spring Boot e Ktor, annotations como @GetMapping e @PostMapping mapeiam funções a rotas HTTP. Testes: @Test, @BeforeEach e @ParameterizedTest do JUnit configuram a execução de testes sem código adicional. Processamento em tempo de compilação: KSP processa annotations para gerar código automaticamente, eliminando boilerplate. Boas Praticas Prefira annotations com AnnotationRetention.SOURCE ou BINARY quando não precisar de reflexao em runtime, pois sao mais eficientes. Use @Target para restringir onde a annotation pode ser aplicada, evitando uso incorreto. Documente o comportamento esperado de annotations customizadas para que outros desenvolvedores saibam como usa-las. Sempre especifique use-site targets (@field:, @get:, @param:) quando trabalhar com frameworks Java que esperam annotations em locais específicos. Considere usar KSP em vez de reflexao para processar annotations, pois o processamento em tempo de compilação e mais performatico. Erros Comuns Esquecer o use-site target: ao usar annotations de frameworks Java em propriedades Kotlin, a annotation pode ir para o getter em vez do campo. Use @field: para garantir o destino correto. Usar RUNTIME retention desnecessariamente: reflexao em runtime tem custo de performance. Se a annotation só e processada em compilação, use SOURCE ou BINARY. Criar annotations sem @Target: sem @Target, a annotation pode ser aplicada em qualquer lugar, o que pode causar confusao. Sempre defina onde ela e válida. Confundir annotation com lógica de negócio: annotations sao metadados, não devem conter lógica. A lógica deve estar no processador da annotation. Perguntas Frequentes Annotations afetam a performance do aplicativo? Annotations com retention SOURCE ou BINARY não afetam a performance em runtime, pois sao removidas ou não acessiveis. Apenas annotations com retention RUNTIME podem ter impacto, especialmente quando processadas via reflexao.\nPosso colocar annotations em lambdas? Nao diretamente em expressoes lambda, mas você pode anotar o parametro de uma função de ordem superior que recebe a lambda, ou anotar a função que contém a lambda.\nQual a diferenca entre annotations do Kotlin e do Java? Annotations do Kotlin sao compatoveis com Java, mas Kotlin adiciona recursos como use-site targets, parametros com valor padrão e suporte nativo a arrays nos parametros da annotation.\nPosso usar annotations com companion objects? Sim. Voce pode anotar membros de companion objects normalmente. Use @JvmStatic para que métodos do companion sejam acessiveis como métodos estaticos em código Java.\n","permalink":"https://kotlin.dev.br/glossario/annotation/","summary":"\u003ch2 id=\"o-que-é-annotation-em-kotlin\"\u003eO que é Annotation em Kotlin?\u003c/h2\u003e\n\u003cp\u003eAnnotations (anotacoes) sao \u003cstrong\u003emetadados\u003c/strong\u003e que você adiciona ao código para fornecer informações extras ao compilador, a ferramentas de build ou a frameworks em tempo de execução. Elas não mudam o comportamento do código diretamente, mas servem como instrucoes pra quem processa o código.\u003c/p\u003e\n\u003cp\u003eSe você já usou \u003ccode\u003e@Override\u003c/code\u003e em Java ou \u003ccode\u003e@Composable\u003c/code\u003e no Jetpack Compose, já usou annotations.\u003c/p\u003e\n\u003cp\u003ePense em annotations como etiquetas coladas em um produto: a etiqueta não muda o produto em si, mas informa quem o manipula (o caixa, o estoquista, o transportador) sobre como trata-lo. Da mesma forma, annotations informam o compilador, frameworks e ferramentas sobre como processar determinado trecho de código.\u003c/p\u003e","title":"Annotation em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que e Enum em Kotlin? Um enum class em Kotlin define um conjunto fixo de constantes. Cada constante é uma instancia única da classe enum, representando um valor possível dentro de um grupo fechado. E ideal pra representar opções predefinidas como dias da semana, estados, categorias, etc.\nPense num semaforo: ele só pode estar vermelho, amarelo ou verde. Nao existe um quarto estado. Um enum faz exatamente isso no código \u0026ndash; define todas as opções possiveis e garante que nenhum valor inválido seja usado. Isso traz seguranca de tipos que simples constantes String ou Int não oferecem.\nEnums em Kotlin vao além de simples listas de constantes. Eles podem ter propriedades, métodos, implementar interfaces e até conter lógica complexa. Combinados com a expressao when, formam uma dupla poderosa para modelar dominios de negócio.\nSintaxe básica enum class Cor { VERMELHO, VERDE, AZUL, AMARELO } fun main() { val minhaCor = Cor.VERDE println(minhaCor) // VERDE println(minhaCor.name) // VERDE println(minhaCor.ordinal) // 1 } Cada constante tem name (o nome como String) e ordinal (a posicao, comecando do zero).\nEnum com propriedades enum class Estado(val sigla: String, val regiao: String) { SAO_PAULO(\u0026#34;SP\u0026#34;, \u0026#34;Sudeste\u0026#34;), RIO_DE_JANEIRO(\u0026#34;RJ\u0026#34;, \u0026#34;Sudeste\u0026#34;), BAHIA(\u0026#34;BA\u0026#34;, \u0026#34;Nordeste\u0026#34;), PARANA(\u0026#34;PR\u0026#34;, \u0026#34;Sul\u0026#34;) } fun main() { val estado = Estado.BAHIA println(\u0026#34;${estado.name}: ${estado.sigla} - ${estado.regiao}\u0026#34;) // BAHIA: BA - Nordeste } Enum com métodos enum class Operacao { SOMA { override fun calcular(a: Double, b: Double) = a + b }, SUBTRACAO { override fun calcular(a: Double, b: Double) = a - b }, MULTIPLICACAO { override fun calcular(a: Double, b: Double) = a * b }; abstract fun calcular(a: Double, b: Double): Double } fun main() { println(Operacao.SOMA.calcular(10.0, 3.0)) // 13.0 println(Operacao.MULTIPLICACAO.calcular(10.0, 3.0)) // 30.0 } Usando com when Enum combina perfeitamente com when:\nenum class StatusPedido { PENDENTE, PROCESSANDO, ENVIADO, ENTREGUE } fun mensagem(status: StatusPedido): String = when (status) { StatusPedido.PENDENTE -\u0026gt; \u0026#34;Aguardando confirmacao\u0026#34; StatusPedido.PROCESSANDO -\u0026gt; \u0026#34;Preparando seu pedido\u0026#34; StatusPedido.ENVIADO -\u0026gt; \u0026#34;Pedido a caminho!\u0026#34; StatusPedido.ENTREGUE -\u0026gt; \u0026#34;Pedido entregue com sucesso\u0026#34; } funções utilitarias // Listar todos os valores Cor.entries.forEach { println(it) } // Converter de String val cor = Cor.valueOf(\u0026#34;AZUL\u0026#34;) println(cor) // AZUL Enum implementando interface Enums podem implementar interfaces, o que permite usar polimorfismo com conjuntos fixos de valores:\ninterface Descritivel { fun descricao(): String } enum class Prioridade : Descritivel { BAIXA { override fun descricao() = \u0026#34;Pode esperar, sem urgencia\u0026#34; }, MEDIA { override fun descricao() = \u0026#34;Resolver em breve\u0026#34; }, ALTA { override fun descricao() = \u0026#34;Resolver o mais rapido possivel\u0026#34; }, CRITICA { override fun descricao() = \u0026#34;Parar tudo e resolver agora\u0026#34; } } fun main() { Prioridade.entries.forEach { p -\u0026gt; println(\u0026#34;${p.name}: ${p.descricao()}\u0026#34;) } } Enum com companion object para busca customizada Muitas vezes você precisa encontrar um enum a partir de um valor que não e o name. Usar um companion object resolve isso:\nenum class Moeda(val codigo: String, val simbolo: String) { REAL(\u0026#34;BRL\u0026#34;, \u0026#34;R$\u0026#34;), DOLAR(\u0026#34;USD\u0026#34;, \u0026#34;$\u0026#34;), EURO(\u0026#34;EUR\u0026#34;, \u0026#34;E\u0026#34;); companion object { fun porCodigo(codigo: String): Moeda? = entries.find { it.codigo == codigo } } } fun main() { val moeda = Moeda.porCodigo(\u0026#34;BRL\u0026#34;) println(\u0026#34;${moeda?.name} - ${moeda?.simbolo}\u0026#34;) // REAL - R$ val desconhecida = Moeda.porCodigo(\u0026#34;GBP\u0026#34;) println(desconhecida) // null } Casos de Uso no Mundo Real Status de pedidos em e-commerce: representar estados como PENDENTE, PAGO, ENVIADO, ENTREGUE e CANCELADO. Cada status pode ter propriedades como cor de exibicao e mensagem para o cliente. Permissoes de usuário: definir niveis de acesso como ADMIN, EDITOR e LEITOR, cada um com um conjunto de permissoes associadas. Dias da semana e meses: usar enums para representar periodos de tempo evita erros de digitacao e garante que apenas valores validos sejam utilizados. Tipos de pagamento: CARTAO_CREDITO, CARTAO_DEBITO, PIX, BOLETO \u0026ndash; cada tipo com suas regras de processamento definidas como métodos abstratos no enum. configuração de ambientes: DESENVOLVIMENTO, HOMOLOGACAO e PRODUCAO, cada um com URLs e credenciais diferentes. Boas Praticas Use enum sempre que tiver um conjunto fixo e conhecido de opções. Evite usar Strings ou Ints magicos para representar estados. Combine enum com when exaustivo. Como o compilador sabe todos os valores possiveis, ele avisa se você esquecer algum caso. Adicione propriedades ao enum em vez de usar when para mapear cada constante a um valor. E mais fácil de manter. Considere sealed classes quando os valores precisam carregar dados diferentes entre si. Enums sao ideais quando todos os valores tem a mesma estrutura. Use entries em vez de values() a partir do Kotlin 1.9, pois entries retorna uma lista imutavel e tem melhor performance. Erros Comuns Usar valueOf() sem tratar exceção: valueOf(\u0026quot;valor_invalido\u0026quot;) lanca IllegalArgumentException. Sempre trate com try-catch ou crie uma função auxiliar que retorne null. Comparar enum por ordinal: nunca use ordinal para lógica de negócio. Se alguem reordenar as constantes, o código quebra silenciosamente. Esquecer o ponto-e-virgula: quando um enum tem membros (métodos ou propriedades) além das constantes, e obrigatório colocar ; apos a ultima constante. Tentar criar instancias em runtime: enums tem um conjunto fixo de instancias. Voce não pode criar Cor(\u0026quot;ROXO\u0026quot;) em tempo de execução. Se precisar disso, considere uma sealed class. Perguntas Frequentes Qual a diferenca entre enum e sealed class? Enums definem um conjunto fixo de instancias unicas, todas com a mesma estrutura. Sealed classes definem um conjunto fixo de tipos, mas cada tipo pode ter propriedades e construtores diferentes. Use enum para valores simples e sealed class para hierarquias mais complexas.\nPosso usar enum em destructuring? Nao diretamente, pois enums não geram funções componentN(). Mas você pode implementa-las manualmente ou usar as propriedades do enum diretamente.\nEnum consome muita memória? Nao. Cada constante e uma instancia única criada quando a classe e carregada. Independentemente de quantas vezes você referência Cor.VERDE, e sempre o mesmo objeto na memória.\nPosso serializar enums com Kotlin Serialization? Sim. Basta anotar o enum com @Serializable. Por padrão, a serialização usa o name da constante. Voce pode customizar com @SerialName em cada constante.\nEnums sao simples, seguros e expressivos. Use sempre que tiver um conjunto fixo de opções no seu dominio.\n","permalink":"https://kotlin.dev.br/glossario/enum/","summary":"\u003ch2 id=\"o-que-e-enum-em-kotlin\"\u003eO que e Enum em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUm \u003ccode\u003eenum class\u003c/code\u003e em Kotlin define um \u003cstrong\u003econjunto fixo de constantes\u003c/strong\u003e. Cada constante é uma instancia única da classe enum, representando um valor possível dentro de um grupo fechado. E ideal pra representar opções predefinidas como dias da semana, estados, categorias, etc.\u003c/p\u003e\n\u003cp\u003ePense num semaforo: ele só pode estar vermelho, amarelo ou verde. Nao existe um quarto estado. Um enum faz exatamente isso no código \u0026ndash; define todas as opções possiveis e garante que nenhum valor inválido seja usado. Isso traz seguranca de tipos que simples constantes String ou Int não oferecem.\u003c/p\u003e","title":"Enum em Kotlin: O que E e Como Funciona | Kotlin Brasil"},{"content":"O que é inline em Kotlin? O modificador inline em Kotlin instrui o compilador a copiar o corpo da função diretamente no local da chamada, em vez de criar uma chamada de função normal. Isso elimina o overhead de criação de objetos para lambdas, melhorando a performance.\nToda vez que você passa uma lambda como argumento, o Kotlin normalmente cria um objeto anônimo. Com inline, esse objeto não é criado — o código da lambda é copiado diretamente.\nSem inline vs com inline // Sem inline: cria um objeto Function para cada chamada fun semInline(bloco: () -\u0026gt; Unit) { bloco() } // Com inline: codigo é copiado no local da chamada inline fun comInline(bloco: () -\u0026gt; Unit) { bloco() } Na prática, o resultado é o mesmo. A diferença é por baixo dos panos: a versão inline não aloca um objeto Function.\nExemplo prático: medindo tempo inline fun medirTempo(bloco: () -\u0026gt; Unit) { val inicio = System.currentTimeMillis() bloco() val fim = System.currentTimeMillis() println(\u0026#34;Tempo: ${fim - inicio}ms\u0026#34;) } fun main() { medirTempo { val soma = (1..1_000_000).sum() println(\u0026#34;Soma: $soma\u0026#34;) } } Non-local return Uma vantagem do inline é permitir non-local return — retornar da função que chamou, não só da lambda:\ninline fun buscarPrimeiro(lista: List\u0026lt;Int\u0026gt;, condicao: (Int) -\u0026gt; Boolean): Int? { for (item in lista) { if (condicao(item)) return item } return null } fun main() { val resultado = buscarPrimeiro(listOf(1, 3, 5, 8, 10)) { it % 2 == 0 } println(resultado) // 8 } noinline e crossinline Se a função tem vários parâmetros lambda e você não quer inlinear todos:\ninline fun exemplo( inlineada: () -\u0026gt; Unit, noinline naoInlineada: () -\u0026gt; Unit ) { inlineada() naoInlineada() } E crossinline impede non-local return em lambdas que serão executadas em outro contexto:\ninline fun executarEmThread(crossinline bloco: () -\u0026gt; Unit) { Thread { bloco() // crossinline impede \u0026#34;return\u0026#34; aqui }.start() } O crossinline é necessário quando a lambda será executada em um contexto diferente (como outra thread ou callback), onde um non-local return não faz sentido e causaria comportamento indefinido.\nQuando usar? Use inline em funções que recebem lambdas como parâmetro e são chamadas com frequência. A biblioteca padrão do Kotlin usa inline em let, apply, map, filter e praticamente todas as scope functions.\nReified type parameters O inline desbloqueia uma funcionalidade exclusiva: os reified type parameters. Normalmente, tipos genéricos são apagados em runtime (type erasure), mas com inline e reified você pode acessá-los:\ninline fun \u0026lt;reified T\u0026gt; converterPara(json: String): T { println(\u0026#34;Convertendo para ${T::class.simpleName}\u0026#34;) // Em um caso real, usaria uma biblioteca como Gson ou kotlinx.serialization throw NotImplementedError(\u0026#34;Exemplo ilustrativo\u0026#34;) } inline fun \u0026lt;reified T\u0026gt; List\u0026lt;*\u0026gt;.filtrarPorTipo(): List\u0026lt;T\u0026gt; { return this.filterIsInstance\u0026lt;T\u0026gt;() } fun main() { val misturado: List\u0026lt;Any\u0026gt; = listOf(1, \u0026#34;texto\u0026#34;, 2.5, \u0026#34;outro\u0026#34;, 3) val strings = misturado.filtrarPorTipo\u0026lt;String\u0026gt;() println(strings) // [texto, outro] val inteiros = misturado.filtrarPorTipo\u0026lt;Int\u0026gt;() println(inteiros) // [1, 3] } Sem inline, seria necessário passar a classe como parâmetro: fun \u0026lt;T\u0026gt; converter(json: String, tipo: Class\u0026lt;T\u0026gt;). Com reified, a API fica muito mais limpa.\nInline properties Além de funções, Kotlin permite marcar getters e setters de propriedades como inline:\nclass Configuracao(private val mapa: Map\u0026lt;String, String\u0026gt;) { inline val versao: String get() = mapa[\u0026#34;versao\u0026#34;] ?: \u0026#34;1.0.0\u0026#34; inline val ambiente: String get() = mapa[\u0026#34;ambiente\u0026#34;] ?: \u0026#34;desenvolvimento\u0026#34; } Isso é útil quando a propriedade não tem backing field e o getter é simples o suficiente para ser copiado no local de uso.\nCasos de Uso no Mundo Real Scope functions da biblioteca padrão: let, run, with, apply e also são todas inline, o que significa que usá-las não tem custo de performance em relação a escrever o código diretamente. DSLs type-safe: frameworks como Jetpack Compose e Ktor usam funções inline para criar DSLs onde o código do usuário é inlineado, mantendo a performance e permitindo non-local returns. Serialização e deserialização: bibliotecas usam inline com reified para inferir o tipo de destino automaticamente, como json.decodeFromString\u0026lt;MeuObjeto\u0026gt;(texto) em kotlinx.serialization. Logging condicional: funções inline de log como logger.debug { \u0026quot;mensagem cara: ${calcular()}\u0026quot; } evitam a construção da string quando o nível de log está desabilitado, já que o lambda só é avaliado se necessário. Boas Práticas Use inline apenas em funções que recebem lambdas. Marcar funções sem parâmetros de função como inline traz pouco benefício e pode aumentar o tamanho do bytecode. Marque com noinline parâmetros lambda que precisam ser armazenados em variáveis, passados para outras funções não-inline ou usados como objetos. Prefira crossinline quando a lambda será executada em outro contexto (threads, callbacks) para evitar bugs sutis com non-local returns. Combine inline com reified para criar APIs mais limpas que não exigem passagem explícita de Class\u0026lt;T\u0026gt; ou KClass\u0026lt;T\u0026gt;. Monitore o tamanho do bytecode gerado. Funções inline muito grandes chamadas em muitos lugares podem aumentar significativamente o tamanho do APK ou JAR. Erros Comuns Tornar todas as funções inline indiscriminadamente: o inline copia o corpo da função em cada local de chamada. Funções grandes inlineadas em muitos lugares inflam o bytecode sem ganho real de performance. Esquecer de marcar parâmetros como noinline quando necessário: se você tenta armazenar uma lambda inline em uma variável ou passá-la para outra função, o compilador gera um erro. A solução é marcar esse parâmetro como noinline. Non-local return inesperado: em funções inline, um return dentro da lambda retorna da função que chamou, não apenas da lambda. Isso pode causar comportamento inesperado se você esperava apenas sair do bloco. Usar inline em funções de interface ou virtuais: funções inline não podem ser open, override ou abstratas, pois o compilador precisa do corpo da função em tempo de compilação para copiar. Confundir reified com reflexão: reified funciona apenas em tempo de compilação dentro de funções inline. Você não pode usar reified em funções não-inline ou armazenar o tipo em uma variável para uso posterior. Perguntas Frequentes O inline melhora a performance de toda função? Não. O benefício principal é evitar a alocação de objetos Function para lambdas. Em funções que não recebem lambdas, o ganho é mínimo e o custo de aumento do bytecode pode não valer a pena.\nQual a diferença entre noinline e crossinline? noinline impede completamente o inlining da lambda, permitindo que ela seja tratada como objeto. crossinline mantém o inlining mas proíbe non-local returns, necessário quando a lambda é executada em outro contexto como uma thread.\nPor que as scope functions do Kotlin são inline? Para que o uso de let, apply, run e similares tenha zero overhead. Sem inline, cada chamada criaria um objeto Function, o que seria inaceitável para funções tão frequentemente utilizadas.\nPosso usar reified sem inline? Não. O modificador reified só funciona em funções inline porque depende do compilador substituir o tipo genérico pelo tipo concreto no local de chamada. Sem inlining, o tipo seria apagado por type erasure.\nTermos Relacionados Higher-Order Function — funções que recebem lambdas e são as principais candidatas para inline Lambda — funções anônimas cujo overhead de alocação é eliminado por inline Generics — tipos genéricos que podem ser preservados em runtime com reified e inline Fun — palavra-chave usada para declarar funções que podem receber o modificador inline ","permalink":"https://kotlin.dev.br/glossario/inline/","summary":"\u003ch2 id=\"o-que-é-inline-em-kotlin\"\u003eO que é \u003ccode\u003einline\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO modificador \u003ccode\u003einline\u003c/code\u003e em Kotlin instrui o compilador a \u003cstrong\u003ecopiar o corpo da função diretamente no local da chamada\u003c/strong\u003e, em vez de criar uma chamada de função normal. Isso elimina o overhead de criação de objetos para lambdas, melhorando a performance.\u003c/p\u003e\n\u003cp\u003eToda vez que você passa uma lambda como argumento, o Kotlin normalmente cria um objeto anônimo. Com \u003ccode\u003einline\u003c/code\u003e, esse objeto não é criado — o código da lambda é copiado diretamente.\u003c/p\u003e","title":"Inline em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é reified em Kotlin? A palavra-chave reified permite acessar informações de tipo genérico em tempo de execução. Normalmente, por causa do type erasure da JVM, tipos genéricos são apagados após a compilação. Com reified, o Kotlin mantém essa informação disponível.\nPara usar reified, a função precisa ser inline. As duas coisas andam juntas.\nO problema sem reified // Isso NÃO funciona: fun \u0026lt;T\u0026gt; ehDoTipo(valor: Any): Boolean { // return valor is T // Erro! Não dá pra checar tipo genérico return false } Na JVM, o tipo T é apagado em tempo de execução. O compilador não sabe qual tipo é T quando o código roda.\nA solução com reified inline fun \u0026lt;reified T\u0026gt; ehDoTipo(valor: Any): Boolean { return valor is T } fun main() { println(ehDoTipo\u0026lt;String\u0026gt;(\u0026#34;Kotlin\u0026#34;)) // true println(ehDoTipo\u0026lt;Int\u0026gt;(\u0026#34;Kotlin\u0026#34;)) // false println(ehDoTipo\u0026lt;Int\u0026gt;(42)) // true } Com reified, o tipo T é conhecido em tempo de execução. Você pode usar is T, T::class e até criar instâncias (com reflexão).\nExemplo prático: parsing de JSON inline fun \u0026lt;reified T\u0026gt; parsear(json: String): T { println(\u0026#34;Parseando para ${T::class.simpleName}\u0026#34;) // Aqui voce usaria uma biblioteca como Gson ou Moshi // return Gson().fromJson(json, T::class.java) throw NotImplementedError(\u0026#34;Exemplo simplificado\u0026#34;) } Sem reified, seria necessário passar Class\u0026lt;T\u0026gt; como parâmetro extra. Com reified, a informação de tipo já tá disponível.\nFiltrando por tipo em coleções inline fun \u0026lt;reified T\u0026gt; List\u0026lt;Any\u0026gt;.filtrarPorTipo(): List\u0026lt;T\u0026gt; { return this.filterIsInstance\u0026lt;T\u0026gt;() } fun main() { val mistura = listOf(1, \u0026#34;Kotlin\u0026#34;, 2.5, \u0026#34;Brasil\u0026#34;, 3, true) val strings = mistura.filtrarPorTipo\u0026lt;String\u0026gt;() println(strings) // [Kotlin, Brasil] val inteiros = mistura.filtrarPorTipo\u0026lt;Int\u0026gt;() println(inteiros) // [1, 3] } Criando instâncias com reified Com reified você pode acessar o construtor de um tipo genérico via reflexão, algo impossível sem essa palavra-chave:\ninline fun \u0026lt;reified T : Any\u0026gt; criarInstancia(): T { val construtor = T::class.constructors.firstOrNull { it.parameters.isEmpty() } ?: throw IllegalArgumentException(\u0026#34;${T::class.simpleName} nao tem construtor sem argumentos\u0026#34;) return construtor.call() } class Motor { val tipo = \u0026#34;V8\u0026#34; override fun toString() = \u0026#34;Motor(tipo=$tipo)\u0026#34; } class Roda { val aro = 17 override fun toString() = \u0026#34;Roda(aro=$aro)\u0026#34; } fun main() { val motor = criarInstancia\u0026lt;Motor\u0026gt;() val roda = criarInstancia\u0026lt;Roda\u0026gt;() println(motor) // Motor(tipo=V8) println(roda) // Roda(aro=17) } Reified com funções de extensão A combinação de reified com funções de extensão cria APIs muito elegantes. Veja um exemplo inspirado em frameworks de injeção de dependência:\nclass Container { private val servicos = mutableMapOf\u0026lt;String, Any\u0026gt;() fun registrar(servico: Any) { servicos[servico::class.qualifiedName ?: \u0026#34;\u0026#34;] = servico } inline fun \u0026lt;reified T : Any\u0026gt; obter(): T { val chave = T::class.qualifiedName return servicos[chave] as? T ?: throw IllegalStateException(\u0026#34;Serviço ${T::class.simpleName} nao registrado\u0026#34;) } } class BancoDeDados { fun consultar(sql: String) = \u0026#34;Resultado de: $sql\u0026#34; } class ServicoDeEmail { fun enviar(para: String) = println(\u0026#34;Email enviado para $para\u0026#34;) } fun main() { val container = Container() container.registrar(BancoDeDados()) container.registrar(ServicoDeEmail()) val db = container.obter\u0026lt;BancoDeDados\u0026gt;() println(db.consultar(\u0026#34;SELECT * FROM usuarios\u0026#34;)) val email = container.obter\u0026lt;ServicoDeEmail\u0026gt;() email.enviar(\u0026#34;karina@kotlin.dev.br\u0026#34;) } Limitações Só funciona com funções inline Não pode ser usado em classes Não pode ser usado com parâmetros noinline Não pode ser chamado a partir de código Java (funções inline com reified não são visíveis para Java) Funções inline com reified não podem ser armazenadas em variáveis de tipo função Casos de Uso no Mundo Real Serialização e desserialização: bibliotecas como Gson, Moshi e kotlinx.serialization usam reified para determinar o tipo de destino ao converter JSON, XML ou outros formatos em objetos Kotlin. Injeção de dependência: frameworks como Koin usam inline fun \u0026lt;reified T\u0026gt; get(): T para resolver dependências sem passar Class\u0026lt;T\u0026gt; explicitamente, tornando a API muito mais limpa. Logging com tipo automático: criar funções de log que automaticamente incluem o nome da classe sem precisar receber parâmetros adicionais, como inline fun \u0026lt;reified T\u0026gt; T.logger() = LoggerFactory.getLogger(T::class.java). Navegação no Android: usar reified para criar funções de navegação tipadas, como inline fun \u0026lt;reified T : Activity\u0026gt; Context.iniciarActivity(), eliminando a necessidade de passar a classe explicitamente. Boas Práticas Use reified apenas quando realmente precisar acessar o tipo em runtime. Se a lógica não depende de T::class, is T ou reflexão, não precisa de reified. Lembre-se de que funções inline com reified são copiadas em cada ponto de chamada. Mantenha o corpo da função enxuto para não inflar o bytecode. Combine com upper bounds (\u0026lt;reified T : AlgumaInterface\u0026gt;) para restringir os tipos aceitos e garantir segurança em tempo de compilação. Prefira reified a receber Class\u0026lt;T\u0026gt; ou KClass\u0026lt;T\u0026gt; como parâmetro. A API fica mais limpa e idiomática. Documente as restrições de tipo quando usar reified em APIs públicas, já que o compilador nem sempre consegue dar mensagens de erro claras sobre tipos incompatíveis. Erros Comuns Esquecer de marcar a função como inline: o compilador vai reclamar, mas a mensagem de erro pode confundir iniciantes. Lembre-se: reified exige inline, sempre. Criar funções inline muito grandes com reified: como o corpo da função é copiado em cada chamada, funções longas geram muito bytecode duplicado. Extraia a lógica não-inline para funções auxiliares. Tentar usar reified em parâmetros de classe: class Repositorio\u0026lt;reified T\u0026gt; não funciona. Reified é exclusivo de funções inline. Para classes, passe KClass\u0026lt;T\u0026gt; no construtor. Assumir que reified funciona com herança de tipos: ehDoTipo\u0026lt;Number\u0026gt;(42) retorna false para is Number em alguns cenários com tipos primitivos, porque a JVM trata primitivos de forma especial. Chamar funções reified a partir de Java: código Java não consegue chamar funções inline com reified. Se sua API precisa ser compatível com Java, forneça uma alternativa que receba Class\u0026lt;T\u0026gt;. Perguntas Frequentes Por que reified precisa de inline? Porque o mecanismo funciona substituindo o corpo da função no ponto de chamada. Ao fazer isso, o compilador conhece o tipo concreto usado e pode inserir a informação de tipo diretamente no bytecode gerado.\nPosso usar reified com múltiplos parâmetros de tipo? Sim. Você pode ter vários parâmetros reified na mesma função, como inline fun \u0026lt;reified A, reified B\u0026gt; converter(valor: A): B. Cada um será resolvido independentemente.\nQual a diferença entre reified e passar Class\u0026lt;T\u0026gt; como parâmetro? Funcionalmente, o resultado é o mesmo. A diferença é ergonomia: com reified, você escreve parsear\u0026lt;Usuario\u0026gt;(json) em vez de parsear(json, Usuario::class.java). O código fica mais limpo e idiomático.\nO reified tem impacto na performance? O impacto é o mesmo do inline em geral: o corpo da função é copiado em cada chamada, o que pode aumentar o tamanho do bytecode mas elimina o overhead de chamada de função. Para funções pequenas, o impacto é negligível ou até positivo.\nTermos Relacionados Inline Function — funções que são expandidas no ponto de chamada, requisito para reified Generics — o sistema de tipos genéricos do Kotlin Extension Function — funções de extensão que combinam bem com reified Reflection — reflexão em Kotlin, frequentemente usada junto com reified reified é uma ferramenta que resolve elegantemente um problema chato da JVM. Sempre que precisar acessar o tipo genérico em runtime, essa é a saída.\n","permalink":"https://kotlin.dev.br/glossario/reified/","summary":"\u003ch2 id=\"o-que-é-reified-em-kotlin\"\u003eO que é \u003ccode\u003ereified\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eA palavra-chave \u003ccode\u003ereified\u003c/code\u003e permite acessar \u003cstrong\u003einformações de tipo genérico em tempo de execução\u003c/strong\u003e. Normalmente, por causa do \u003cem\u003etype erasure\u003c/em\u003e da JVM, tipos genéricos são apagados após a compilação. Com \u003ccode\u003ereified\u003c/code\u003e, o Kotlin mantém essa informação disponível.\u003c/p\u003e\n\u003cp\u003ePara usar \u003ccode\u003ereified\u003c/code\u003e, a função precisa ser \u003ccode\u003einline\u003c/code\u003e. As duas coisas andam juntas.\u003c/p\u003e\n\u003ch3 id=\"o-problema-sem-reified\"\u003eO problema sem reified\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Isso NÃO funciona:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nc\"\u003eT\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"nf\"\u003eehDoTipo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalor\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eAny\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e \u003cspan class=\"n\"\u003eBoolean\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e// return valor is T  // Erro! Não dá pra checar tipo genérico\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"k\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eNa JVM, o tipo \u003ccode\u003eT\u003c/code\u003e é apagado em tempo de execução. O compilador não sabe qual tipo é \u003ccode\u003eT\u003c/code\u003e quando o código roda.\u003c/p\u003e","title":"Reified em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que e DSL em Kotlin? DSL significa Domain-Specific Language \u0026ndash; uma linguagem específica de dominio. Em Kotlin, você pode criar DSLs usando lambdas com receiver e extension functions, resultando em código que parece quase uma linguagem natural para determinada tarefa.\nSe você já usou Gradle com Kotlin Script ou escreveu testes com Kotest, já viu DSLs em acao.\nPense numa DSL como um formulario bem desenhado: em vez de escrever texto livre, você preenche campos estruturados que guiam a resposta. A DSL faz isso com código \u0026ndash; cria uma estrutura para expressar intencoes de forma clara e restrita ao dominio.\nO segredo por tras das DSLs em Kotlin esta na combinacao de lambdas com receiver, higher-order functions e extension functions. Esses tres recursos juntos permitem criar APIs que parecem uma linguagem própria.\nExemplo simples: construtor de HTML class HTML { private val elementos = mutableListOf\u0026lt;String\u0026gt;() fun head(titulo: String) { elementos.add(\u0026#34;\u0026lt;head\u0026gt;\u0026lt;title\u0026gt;$titulo\u0026lt;/title\u0026gt;\u0026lt;/head\u0026gt;\u0026#34;) } fun body(conteudo: Body.() -\u0026gt; Unit) { val body = Body() body.conteudo() elementos.add(\u0026#34;\u0026lt;body\u0026gt;${body.render()}\u0026lt;/body\u0026gt;\u0026#34;) } fun render() = \u0026#34;\u0026lt;html\u0026gt;${elementos.joinToString(\u0026#34;\u0026#34;)}\u0026lt;/html\u0026gt;\u0026#34; } class Body { private val itens = mutableListOf\u0026lt;String\u0026gt;() fun p(texto: String) { itens.add(\u0026#34;\u0026lt;p\u0026gt;$texto\u0026lt;/p\u0026gt;\u0026#34;) } fun h1(texto: String) { itens.add(\u0026#34;\u0026lt;h1\u0026gt;$texto\u0026lt;/h1\u0026gt;\u0026#34;) } fun render() = itens.joinToString(\u0026#34;\u0026#34;) } fun html(bloco: HTML.() -\u0026gt; Unit): String { val pagina = HTML() pagina.bloco() return pagina.render() } E o uso fica assim:\nfun main() { val pagina = html { head(\u0026#34;Kotlin Brasil\u0026#34;) body { h1(\u0026#34;Bem-vindo!\u0026#34;) p(\u0026#34;Aprenda Kotlin de um jeito brasileiro.\u0026#34;) } } println(pagina) } Repare como o código fica expressivo \u0026ndash; quase como escrever HTML de verdade.\nA magica: lambdas com receiver O segredo das DSLs em Kotlin e a lambda com receiver. Quando você declara HTML.() -\u0026gt; Unit, esta dizendo que dentro do bloco, o this e uma instancia de HTML. Isso permite chamar os métodos diretamente, sem prefixo.\nExemplo prático: configuração class DatabaseConfig { var host = \u0026#34;localhost\u0026#34; var porta = 5432 var nome = \u0026#34;\u0026#34; } fun database(config: DatabaseConfig.() -\u0026gt; Unit): DatabaseConfig { return DatabaseConfig().apply(config) } fun main() { val db = database { host = \u0026#34;db.kotlin.dev.br\u0026#34; porta = 5433 nome = \u0026#34;kotlin_brasil\u0026#34; } println(\u0026#34;${db.host}:${db.porta}/${db.nome}\u0026#34;) } Exemplo: DSL para definicao de rotas HTTP Um caso muito comum em frameworks web e a definicao de rotas usando DSL. Veja como ficaria uma versão simplificada:\nclass Router { private val rotas = mutableListOf\u0026lt;String\u0026gt;() fun get(caminho: String, handler: () -\u0026gt; String) { rotas.add(\u0026#34;GET $caminho -\u0026gt; ${handler()}\u0026#34;) } fun post(caminho: String, handler: () -\u0026gt; String) { rotas.add(\u0026#34;POST $caminho -\u0026gt; ${handler()}\u0026#34;) } fun listar() = rotas.forEach(::println) } fun router(config: Router.() -\u0026gt; Unit): Router { return Router().apply(config) } fun main() { val api = router { get(\u0026#34;/usuarios\u0026#34;) { \u0026#34;Lista de usuarios\u0026#34; } get(\u0026#34;/usuarios/{id}\u0026#34;) { \u0026#34;Detalhes do usuario\u0026#34; } post(\u0026#34;/usuarios\u0026#34;) { \u0026#34;Criar usuario\u0026#34; } } api.listar() } Exemplo: DSL para construcao de queries class Query { private var tabela = \u0026#34;\u0026#34; private val condicoes = mutableListOf\u0026lt;String\u0026gt;() private var limite: Int? = null fun from(nome: String) { tabela = nome } fun where(condicao: String) { condicoes.add(condicao) } fun limit(n: Int) { limite = n } fun build(): String { val sql = StringBuilder(\u0026#34;SELECT * FROM $tabela\u0026#34;) if (condicoes.isNotEmpty()) { sql.append(\u0026#34; WHERE ${condicoes.joinToString(\u0026#34; AND \u0026#34;)}\u0026#34;) } limite?.let { sql.append(\u0026#34; LIMIT $it\u0026#34;) } return sql.toString() } } fun query(config: Query.() -\u0026gt; Unit): String { return Query().apply(config).build() } fun main() { val sql = query { from(\u0026#34;pedidos\u0026#34;) where(\u0026#34;status = \u0026#39;ativo\u0026#39;\u0026#34;) where(\u0026#34;valor \u0026gt; 100\u0026#34;) limit(10) } println(sql) // SELECT * FROM pedidos WHERE status = \u0026#39;ativo\u0026#39; AND valor \u0026gt; 100 LIMIT 10 } Controlando o escopo com @DslMarker Quando você tem DSLs aninhadas, pode acontecer de o usuário acessar funções do escopo externo dentro do escopo interno por engano. A anotacao @DslMarker resolve isso:\n@DslMarker annotation class HtmlDsl @HtmlDsl class Table { fun tr(block: Row.() -\u0026gt; Unit) { /* ... */ } } @HtmlDsl class Row { fun td(texto: String) { /* ... */ } } Com @DslMarker, dentro de um bloco tr { } você só tem acesso aos métodos de Row, não aos de Table. Isso evita erros e deixa a DSL mais segura.\nCasos de Uso no Mundo Real Gradle Kotlin DSL: toda a configuração de build do Gradle pode ser feita com Kotlin DSL, incluindo dependências, plugins e tarefas customizadas. Jetpack Compose: a UI declarativa do Android usa DSLs extensivamente. Cada Composable e essencialmente uma DSL para construir interfaces. Ktor: o framework web da JetBrains usa DSL para definir rotas, configurar servidores e serializar dados. Kotest: framework de testes que usa DSL para descrever testes de forma expressiva, similar ao RSpec do Ruby. Exposed: framework de banco de dados da JetBrains que usa DSL type-safe para construir queries SQL. Boas Praticas Mantenha a DSL focada em um único dominio. Uma DSL que tenta fazer tudo vira uma GPL mal feita. Use @DslMarker para controlar o escopo e evitar que o usuário acesse funções de contextos externos indevidamente. Documente a DSL com exemplos claros, pois a sintaxe pode não ser obvia para quem não conhece a API. Prefira nomes que leiam como linguagem natural. get(\u0026quot;/rota\u0026quot;) e melhor do que adicionarRotaGet(\u0026quot;/rota\u0026quot;). Erros Comuns Nao usar @DslMarker: sem essa anotacao, o usuário pode chamar funções do escopo externo dentro de blocos aninhados, causando comportamento inesperado. DSL complexa demais: se o usuário precisa ler a documentação inteira pra entender como usar, a DSL esta complicada demais. Simplifique. Confundir DSL com builder pattern: embora DSLs possam usar builders, nem todo builder e uma DSL. A DSL deve ter uma sintaxe que faça sentido no dominio. Esquecer de validar entradas: como a DSL permite ao usuário preencher campos livremente, e essencial validar os dados no momento da construcao do objeto final. Perguntas Frequentes Qual a diferenca entre DSL e API fluente? Uma API fluente usa encadeamento de métodos (method chaining), enquanto uma DSL usa lambdas com receiver para criar blocos de código que leem como uma linguagem própria. Em Kotlin, DSLs sao mais poderosas porque permitem aninhamento natural.\nPreciso saber generics para criar DSLs? Nao necessariamente para DSLs simples, mas generics ajudam muito quando você quer criar DSLs reutilizaveis e type-safe. Muitas DSLs avancadas combinam generics com inline functions.\nDSLs afetam a performance? Minimamente. Como as lambdas com receiver sao compiladas para classes anonimas na JVM, há uma pequena alocacao de memória. Usando funções inline, esse custo e eliminado, pois o compilador insere o código diretamente no local da chamada.\nPosso criar DSLs que funcionem em Kotlin Multiplatform? Sim. Como DSLs sao construidas com recursos da própria linguagem Kotlin (lambdas, extension functions, receivers), elas funcionam em todas as plataformas suportadas pelo Kotlin, incluindo JVM, JS e Native.\nDSLs em Kotlin sao poderosas para configuracoes, builders de UI, definicao de rotas em servidores web e muito mais. E uma das features que mais diferencia Kotlin de outras linguagens.\n","permalink":"https://kotlin.dev.br/glossario/dsl/","summary":"\u003ch2 id=\"o-que-e-dsl-em-kotlin\"\u003eO que e DSL em Kotlin?\u003c/h2\u003e\n\u003cp\u003eDSL significa \u003cstrong\u003eDomain-Specific Language\u003c/strong\u003e \u0026ndash; uma linguagem específica de dominio. Em Kotlin, você pode criar DSLs usando lambdas com receiver e \u003ca href=\"/glossario/extension-function/\"\u003eextension functions\u003c/a\u003e, resultando em código que parece quase uma linguagem natural para determinada tarefa.\u003c/p\u003e\n\u003cp\u003eSe você já usou Gradle com Kotlin Script ou escreveu testes com Kotest, já viu DSLs em acao.\u003c/p\u003e\n\u003cp\u003ePense numa DSL como um formulario bem desenhado: em vez de escrever texto livre, você preenche campos estruturados que guiam a resposta. A DSL faz isso com código \u0026ndash; cria uma estrutura para expressar intencoes de forma clara e restrita ao dominio.\u003c/p\u003e","title":"DSL em Kotlin: O que E e Como Funciona | Kotlin Brasil"},{"content":"O que é Higher-Order Function em Kotlin? Uma Higher-Order Function (função de ordem superior) é uma função que recebe outra função como parâmetro ou retorna uma função. Em Kotlin, funções são cidadãs de primeira classe, então esse tipo de construção é super natural.\nVocê já usa higher-order functions sem perceber: map, filter, forEach — todas elas recebem lambdas como argumento.\nRecebendo funções como parâmetro fun executarOperacao(a: Int, b: Int, operacao: (Int, Int) -\u0026gt; Int): Int { return operacao(a, b) } fun main() { val soma = executarOperacao(10, 5) { a, b -\u0026gt; a + b } val produto = executarOperacao(10, 5) { a, b -\u0026gt; a * b } println(\u0026#34;Soma: $soma\u0026#34;) // Soma: 15 println(\u0026#34;Produto: $produto\u0026#34;) // Produto: 50 } O tipo (Int, Int) -\u0026gt; Int declara que o parâmetro é uma função que recebe dois inteiros e retorna um inteiro.\nRetornando funções fun criarMultiplicador(fator: Int): (Int) -\u0026gt; Int { return { numero -\u0026gt; numero * fator } } fun main() { val dobrar = criarMultiplicador(2) val triplicar = criarMultiplicador(3) println(dobrar(5)) // 10 println(triplicar(5)) // 15 } Aqui, criarMultiplicador retorna uma função. Cada vez que você chama, recebe uma função nova configurada com o fator escolhido.\nExemplo prático: válidação fun validar(valor: String, vararg regras: (String) -\u0026gt; Boolean): Boolean { return regras.all { regra -\u0026gt; regra(valor) } } fun main() { val naoVazio: (String) -\u0026gt; Boolean = { it.isNotBlank() } val tamanhoMinimo: (String) -\u0026gt; Boolean = { it.length \u0026gt;= 3 } val semEspaco: (String) -\u0026gt; Boolean = { !it.contains(\u0026#34; \u0026#34;) } println(validar(\u0026#34;kotlin\u0026#34;, naoVazio, tamanhoMinimo, semEspaco)) // true println(validar(\u0026#34;ab\u0026#34;, naoVazio, tamanhoMinimo)) // false println(validar(\u0026#34;tem espaco\u0026#34;, naoVazio, semEspaco)) // false } Referência de função com :: Você pode passar funções já existentes usando :::\nfun ehPositivo(n: Int) = n \u0026gt; 0 fun main() { val numeros = listOf(-2, -1, 0, 1, 2) val positivos = numeros.filter(::ehPositivo) println(positivos) // [1, 2] } Funções com receiver como parâmetro Higher-order functions podem receber funções com receiver, criando blocos de código que têm acesso ao contexto de um objeto específico:\nfun configurar(builder: StringBuilder.() -\u0026gt; Unit): String { val sb = StringBuilder() sb.builder() return sb.toString() } fun main() { val html = configurar { append(\u0026#34;\u0026lt;html\u0026gt;\u0026#34;) append(\u0026#34;\u0026lt;body\u0026gt;\u0026#34;) append(\u0026#34;\u0026lt;h1\u0026gt;Kotlin Brasil\u0026lt;/h1\u0026gt;\u0026#34;) append(\u0026#34;\u0026lt;/body\u0026gt;\u0026#34;) append(\u0026#34;\u0026lt;/html\u0026gt;\u0026#34;) } println(html) } Esse padrão é a base das DSLs em Kotlin. O bloco passado como argumento executa no contexto do StringBuilder, tendo acesso direto a todos os seus métodos.\nComposição de funções Higher-order functions permitem compor funções menores para criar operações mais complexas:\nfun \u0026lt;T\u0026gt; compor( f: (T) -\u0026gt; T, g: (T) -\u0026gt; T ): (T) -\u0026gt; T { return { valor -\u0026gt; f(g(valor)) } } fun main() { val dobrar: (Int) -\u0026gt; Int = { it * 2 } val somar10: (Int) -\u0026gt; Int = { it + 10 } val dobrarEsomar = compor(somar10, dobrar) println(dobrarEsomar(5)) // 20 (5*2=10, 10+10=20) val somarEdobrar = compor(dobrar, somar10) println(somarEdobrar(5)) // 30 (5+10=15, 15*2=30) } Casos de Uso no Mundo Real Middleware em servidores web: frameworks como Ktor usam higher-order functions para definir pipelines de processamento de requisições, onde cada middleware recebe a próxima função do pipeline como parâmetro. Callbacks de eventos no Android: listeners de clique, animações e operações assíncronas são implementados como higher-order functions, substituindo interfaces anônimas do Java por lambdas concisas. Estratégias de retry e circuit breaker: funções que encapsulam a lógica de repetição recebem a operação a ser executada como parâmetro, permitindo aplicar políticas de retry a qualquer chamada de rede ou banco de dados. Transformação de dados em pipelines: operações de ETL e processamento de dados usam cadeias de higher-order functions como map, flatMap, groupBy e fold para transformar coleções de forma declarativa. Boas Práticas Marque higher-order functions com inline quando elas recebem lambdas e são chamadas com frequência, para evitar a criação de objetos Function desnecessários. Use tipos de função descritivos com typealias para melhorar a legibilidade: typealias Validador = (String) -\u0026gt; Boolean é mais claro que repetir (String) -\u0026gt; Boolean em vários lugares. Prefira trailing lambda syntax quando a função tem apenas um parâmetro lambda ou quando o lambda é o parâmetro mais importante. Mantenha os tipos de função simples. Se uma higher-order function precisa de mais de 3 ou 4 parâmetros na função recebida, considere criar uma data class ou interface. Documente o contrato esperado do parâmetro de função, especialmente se ele tem efeitos colaterais ou restrições de thread. Erros Comuns Esquecer o overhead de lambdas não-inline: cada lambda passada como argumento para uma função não-inline cria um objeto na heap. Em loops apertados, isso pode causar pressão no garbage collector. Use inline nesses casos. Aninhar muitas higher-order functions: código como lista.map { }.filter { }.flatMap { }.groupBy { }.mapValues { } pode se tornar difícil de depurar. Quebre em variáveis intermediárias quando a cadeia ficar longa. Confundir referência de função com chamada de função: ::minhaFuncao é uma referência (pode ser passada como argumento), enquanto minhaFuncao() é uma chamada (executa e retorna o resultado). Não considerar a nullable na assinatura: se a função recebida pode ser nula, o tipo deve ser ((Int) -\u0026gt; Int)?. Sem isso, o compilador não aceita null como argumento. Capturar variáveis mutáveis em lambdas: lambdas que capturam variáveis var podem causar comportamentos inesperados se executadas em threads diferentes ou em momentos posteriores. Perguntas Frequentes Qual a diferença entre higher-order function e lambda? Uma higher-order function é uma função que recebe ou retorna outras funções. Uma lambda é uma forma de criar uma função anônima. Lambdas são frequentemente passadas como argumento para higher-order functions, mas são conceitos distintos.\nHigher-order functions afetam a performance? Sem o modificador inline, cada lambda cria um objeto na JVM. Para funções chamadas poucas vezes, o impacto é desprezível. Para hot paths (loops internos, processamento de alto volume), use inline para eliminar esse overhead.\nPosso usar higher-order functions com coroutines? Sim. Você pode receber funções suspensas como parâmetro usando o tipo suspend () -\u0026gt; T. Isso é muito comum em APIs de coroutines, como withContext, launch e async.\nO que é trailing lambda syntax? Quando o último parâmetro de uma função é uma lambda, você pode escrevê-la fora dos parênteses. Se a lambda é o único argumento, os parênteses podem ser omitidos completamente: lista.forEach { println(it) }.\nTermos Relacionados Lambda — funções anônimas frequentemente passadas como argumento para higher-order functions Fun — palavra-chave usada para declarar higher-order functions Inline — modificador que otimiza higher-order functions eliminando o overhead de lambdas Flow — API baseada em higher-order functions para streams de dados assíncronos Higher-order functions são o alicerce da programação funcional em Kotlin. Elas tornam o código mais flexível, reutilizável e expressivo.\n","permalink":"https://kotlin.dev.br/glossario/higher-order-function/","summary":"\u003ch2 id=\"o-que-é-higher-order-function-em-kotlin\"\u003eO que é Higher-Order Function em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUma \u003cstrong\u003eHigher-Order Function\u003c/strong\u003e (função de ordem superior) é uma função que \u003cstrong\u003erecebe outra função como parâmetro\u003c/strong\u003e ou \u003cstrong\u003eretorna uma função\u003c/strong\u003e. Em Kotlin, funções são cidadãs de primeira classe, então esse tipo de construção é super natural.\u003c/p\u003e\n\u003cp\u003eVocê já usa higher-order functions sem perceber: \u003ccode\u003emap\u003c/code\u003e, \u003ccode\u003efilter\u003c/code\u003e, \u003ccode\u003eforEach\u003c/code\u003e — todas elas recebem lambdas como argumento.\u003c/p\u003e\n\u003ch3 id=\"recebendo-funções-como-parâmetro\"\u003eRecebendo funções como parâmetro\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003eexecutarOperacao\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eoperacao\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eoperacao\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003esoma\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eexecutarOperacao\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"p\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003eproduto\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eexecutarOperacao\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"p\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Soma: \u003c/span\u003e\u003cspan class=\"si\"\u003e$soma\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e       \u003cspan class=\"c1\"\u003e// Soma: 15\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Produto: \u003c/span\u003e\u003cspan class=\"si\"\u003e$produto\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Produto: 50\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eO tipo \u003ccode\u003e(Int, Int) -\u0026gt; Int\u003c/code\u003e declara que o parâmetro é uma função que recebe dois inteiros e retorna um inteiro.\u003c/p\u003e","title":"Higher-Order Function em Kotlin: O que É | Kotlin Brasil"},{"content":"O que e Extension Function em Kotlin? Extension Functions permitem adicionar novas funções a classes existentes sem precisar herdar delas ou usar padrões como Decorator. Voce estende o comportamento de qualquer classe \u0026ndash; inclusive as que não sao suas, como String, Int ou List.\nE uma das funcionalidades mais elegantes do Kotlin é uma das que mais faz a galera se apaixonar pela linguagem.\nImagine que você comprou uma estante pronta. Voce não pode modificar o projeto original da fabrica, mas pode parafusar uma prateleira extra nela. Extension functions fazem isso com classes: adicionam comportamento novo sem alterar o código original. A classe não sabe que foi estendida, mas quem usa ganha uma função nova disponivel como se fosse nativa.\nEsse recurso e fundamental para criar DSLs, APIs fluentes e utilitarios reutilizaveis. A própria biblioteca padrão do Kotlin e repleta de extension functions \u0026ndash; funções como let, also, map e filter em colecoes sao todas extensions.\nSintaxe básica fun String.contarPalavras(): Int { return this.trim().split(\u0026#34;\\\\s+\u0026#34;.toRegex()).size } fun main() { val frase = \u0026#34;Kotlin e muito massa\u0026#34; println(frase.contarPalavras()) // 4 } A função contarPalavras() agora pode ser chamada em qualquer String, como se fizesse parte da classe original. O this dentro da função se refere ao objeto em que ela foi chamada.\nExtension em tipos numericos fun Double.formatarReais(): String { return \u0026#34;R$ ${\u0026#34;%.2f\u0026#34;.format(this)}\u0026#34; } fun Int.ehPar(): Boolean = this % 2 == 0 fun main() { println(1599.90.formatarReais()) // R$ 1599.90 println(42.ehPar()) // true println(7.ehPar()) // false } Extension em colecoes fun \u0026lt;T\u0026gt; List\u0026lt;T\u0026gt;.segundoOuNull(): T? { return if (this.size \u0026gt;= 2) this[1] else null } fun main() { val nomes = listOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;, \u0026#34;Carlos\u0026#34;) println(nomes.segundoOuNull()) // Bruno val vazia = emptyList\u0026lt;String\u0026gt;() println(vazia.segundoOuNull()) // null } Como funciona por tras Na real, extension functions sao resolvidas estaticamente. O compilador transforma a função numa função estática com o objeto como primeiro parametro. Isso significa que elas não suportam polimorfismo \u0026ndash; e a classe declarada que conta, não a real.\nopen class Animal class Cachorro : Animal() fun Animal.som() = \u0026#34;...\u0026#34; fun Cachorro.som() = \u0026#34;Au au!\u0026#34; fun fazerSom(animal: Animal) = animal.som() fun main() { println(fazerSom(Cachorro())) // \u0026#34;...\u0026#34; -- usa o tipo declarado } Extension Properties Alem de funções, você pode criar propriedades de extensao. Elas não armazenam estado (não tem backing field), mas podem calcular valores:\nval String.primeiraLetraMaiuscula: String get() = if (isNotEmpty()) { this[0].uppercase() + substring(1) } else { this } val List\u0026lt;Int\u0026gt;.media: Double get() = if (isNotEmpty()) sum().toDouble() / size else 0.0 fun main() { println(\u0026#34;kotlin\u0026#34;.primeiraLetraMaiuscula) // Kotlin println(listOf(10, 20, 30).media) // 20.0 } Extension Functions com generics Extensions combinadas com generics permitem criar funções reutilizaveis para qualquer tipo:\nfun \u0026lt;T\u0026gt; T.tambemLogar(tag: String = \u0026#34;LOG\u0026#34;): T { println(\u0026#34;[$tag] $this\u0026#34;) return this } fun \u0026lt;T\u0026gt; List\u0026lt;T\u0026gt;.agruparEmPares(): List\u0026lt;List\u0026lt;T\u0026gt;\u0026gt; { return chunked(2) } fun main() { val resultado = 42.tambemLogar(\u0026#34;Numero\u0026#34;) // [Numero] 42 println(resultado) // 42 val pares = listOf(\u0026#34;A\u0026#34;, \u0026#34;B\u0026#34;, \u0026#34;C\u0026#34;, \u0026#34;D\u0026#34;, \u0026#34;E\u0026#34;).agruparEmPares() println(pares) // [[A, B], [C, D], [E]] } Extension Functions em tipos nullable Voce pode criar extensions que funcionam mesmo quando o objeto e null:\nfun String?.ouPadrao(padrao: String = \u0026#34;N/A\u0026#34;): String { return this ?: padrao } fun main() { val nome: String? = null val apelido: String? = \u0026#34;Kari\u0026#34; println(nome.ouPadrao()) // N/A println(apelido.ouPadrao()) // Kari println(nome.ouPadrao(\u0026#34;Sem nome\u0026#34;)) // Sem nome } Casos de Uso no Mundo Real Formatacao de dados: criar extensions como Date.formatarBrasileiro() ou Double.formatarMoeda() que encapsulam regras de formatacao usadas em todo o projeto. Validacao: funções como String.ehCpfValido() ou String.ehEmailValido() que centralizam lógica de validacao e podem ser chamadas de qualquer lugar. Android e Jetpack: extensions como View.esconder(), View.mostrar(), Context.toast() sao extremamente comuns em projetos Android para reduzir boilerplate. Conversao de tipos: funções como String.toUsuario() ou Map.toConfig() que transformam dados brutos em objetos de dominio usando data classes. Testes: criar extensions que facilitam assercoes, como List.deveConter(item) ou String.deveSerVazia(). Boas Praticas Use extension functions para adicionar comportamento a classes que você não controla. Se você controla a classe, avalie se a função não deveria ser um método normal. Mantenha extensions em arquivos organizados por tipo (por exemplo, StringExtensions.kt, ListExtensions.kt). Isso facilita a descoberta e reutilização. Evite criar extensions que dependem de estado externo ou efeitos colaterais. Extensions devem ser previsiveis e puras sempre que possível. Prefira extensions a funções utilitarias com o objeto como parametro. email.ehValido() e mais natural que ehValido(email). Documente suas extensions, especialmente as que serao usadas por outros desenvolvedores. O autocomplete da IDE mostra extensions, mas sem documentação pode ser difícil entender o que cada uma faz. Erros Comuns Esperar comportamento polimorfico: como extensions sao resolvidas estaticamente, chamar animal.som() sempre usa o tipo declarado da variavel, não o tipo real do objeto. Se precisar de polimorfismo, use métodos de instancia ou interfaces. Criar extensions demais: adicionar dezenas de extensions a String ou List polui o autocomplete da IDE e dificulta a manutenção. Seja seletivo. Conflito com métodos existentes: se uma extension tem a mesma assinatura que um método da classe, o método da classe sempre vence. A extension nunca sera chamada, sem nenhum aviso do compilador. Nao importar a extension: extensions precisam ser importadas para serem usadas fora do arquivo onde foram declaradas. Esquecimento de import e um erro frequente. Perguntas Frequentes Extension functions alteram a classe original? Nao. A classe original permanece intacta. O compilador transforma a extension em uma função estática que recebe o objeto como primeiro parametro. E apenas acucar sintatico.\nPosso criar extension functions para companion objects? Sim. Voce pode estender o companion object de uma classe, permitindo chamar a extension como se fosse uma função estática: MinhaClasse.minhaExtension().\nExtensions funcionam em Kotlin Multiplatform? Sim. Extensions sao um recurso da linguagem Kotlin e funcionam em todas as plataformas: JVM, JS e Native. Elas sao especialmente úteis para criar APIs consistentes entre plataformas usando expect/actual.\nQual a diferenca entre extension function e higher-order function? Sao conceitos diferentes. Extension functions adicionam funções a tipos existentes. Higher-order functions recebem ou retornam funções como parametro. Porem, elas se combinam muito bem \u0026ndash; por exemplo, List.filter {} e uma extension function que recebe uma lambda como parametro.\nQuando usar? Use extension functions para adicionar utilidades a classes que você não controla, criar APIs mais fluentes e manter o código organizado. A biblioteca padrão do Kotlin e cheia delas.\n","permalink":"https://kotlin.dev.br/glossario/extension-function/","summary":"\u003ch2 id=\"o-que-e-extension-function-em-kotlin\"\u003eO que e Extension Function em Kotlin?\u003c/h2\u003e\n\u003cp\u003eExtension Functions permitem \u003cstrong\u003eadicionar novas funções a classes existentes\u003c/strong\u003e sem precisar herdar delas ou usar padrões como Decorator. Voce estende o comportamento de qualquer classe \u0026ndash; inclusive as que não sao suas, como \u003ccode\u003eString\u003c/code\u003e, \u003ccode\u003eInt\u003c/code\u003e ou \u003ccode\u003eList\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eE uma das funcionalidades mais elegantes do Kotlin é uma das que mais faz a galera se apaixonar pela linguagem.\u003c/p\u003e\n\u003cp\u003eImagine que você comprou uma estante pronta. Voce não pode modificar o projeto original da fabrica, mas pode parafusar uma prateleira extra nela. Extension functions fazem isso com classes: adicionam comportamento novo sem alterar o código original. A classe não sabe que foi estendida, mas quem usa ganha uma função nova disponivel como se fosse nativa.\u003c/p\u003e","title":"Extension Function em Kotlin: O que E e Como Funciona | Kotlin Brasil"},{"content":"O que é Lambda em Kotlin? Uma lambda é uma função anônima — uma função sem nome que pode ser tratada como valor. Você pode armazená-la em variáveis, passá-la como argumento ou retorná-la de outra função. Lambdas são a base da programação funcional em Kotlin.\nA sintaxe é simples: tudo fica entre chaves {}, com os parâmetros antes da seta -\u0026gt; é o corpo depois.\nSintaxe básica val saudacao = { nome: String -\u0026gt; \u0026#34;Olá, $nome!\u0026#34; } fun main() { println(saudacao(\u0026#34;Karina\u0026#34;)) // Olá, Karina! } Lambda como argumento O uso mais comum de lambdas é como argumento de funções, especialmente com coleções:\nfun main() { val numeros = listOf(1, 2, 3, 4, 5, 6) val pares = numeros.filter { it % 2 == 0 } println(pares) // [2, 4, 6] val dobrados = numeros.map { it * 2 } println(dobrados) // [2, 4, 6, 8, 10, 12] } Quando a lambda tem um único parâmetro, você pode usar it em vez de declarar o nome.\nTrailing lambda Se o último parâmetro de uma função é uma lambda, você pode escrevê-la fora dos parênteses:\nval nomes = listOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;, \u0026#34;Carla\u0026#34;) // Essas duas formas são equivalentes: nomes.forEach({ println(it) }) nomes.forEach { println(it) } // Mais idiomático Essa convenção deixa o código mais limpo e é usada em toda parte no Kotlin.\nLambda com múltiplos parâmetros val soma = { a: Int, b: Int -\u0026gt; a + b } println(soma(3, 7)) // 10 val nomes = mapOf(\u0026#34;BR\u0026#34; to \u0026#34;Brasil\u0026#34;, \u0026#34;PT\u0026#34; to \u0026#34;Portugal\u0026#34;) nomes.forEach { (codigo, pais) -\u0026gt; println(\u0026#34;$codigo -\u0026gt; $pais\u0026#34;) } Lambda com receiver Kotlin suporta lambdas com receiver, que são a base das DSLs:\nfun construirTexto(bloco: StringBuilder.() -\u0026gt; Unit): String { val sb = StringBuilder() sb.bloco() return sb.toString() } fun main() { val texto = construirTexto { append(\u0026#34;Kotlin \u0026#34;) append(\u0026#34;Brasil!\u0026#34;) } println(texto) // Kotlin Brasil! } Captura de variáveis (closure) Lambdas em Kotlin podem acessar e modificar variáveis do escopo externo, formando o que se chama de closure:\nfun criarContador(): () -\u0026gt; Int { var contagem = 0 return { contagem++ contagem } } fun main() { val contador = criarContador() println(contador()) // 1 println(contador()) // 2 println(contador()) // 3 } Diferente de Java, onde variáveis capturadas devem ser efetivamente finais, Kotlin permite que lambdas modifiquem variáveis var do escopo externo. Isso é possível porque o compilador encapsula a variável em um objeto wrapper.\nLambda vs função anônima Kotlin também oferece funções anônimas, que são semelhantes a lambdas mas com sintaxe diferente e comportamento de return distinto:\nfun main() { val numeros = listOf(1, 2, 3, 4, 5) // Lambda: \u0026#34;return\u0026#34; faz non-local return (se inline) numeros.forEach { if (it == 3) return@forEach // Label necessario para sair só do lambda println(it) } // Função anônima: \u0026#34;return\u0026#34; retorna da funcao anônima numeros.forEach(fun(numero) { if (numero == 3) return // Retorna apenas desta funcao anônima println(numero) }) } A principal diferença prática: em lambdas, return sem label retorna da função envolvente (se inline). Em funções anônimas, return sempre retorna da própria função anônima.\nSAM conversion Kotlin converte lambdas automaticamente para interfaces Java com um único método abstrato (SAM - Single Abstract Method):\n// Interface Java funcional // public interface OnClickListener { void onClick(View view); } // Em vez de criar uma classe anônima: button.setOnClickListener { view -\u0026gt; println(\u0026#34;Botão clicado!\u0026#34;) } Para interfaces Kotlin, a conversão SAM funciona quando a interface é declarada com fun interface:\nfun interface Transformador\u0026lt;T\u0026gt; { fun transformar(valor: T): T } fun aplicar(valor: Int, transformador: Transformador\u0026lt;Int\u0026gt;): Int { return transformador.transformar(valor) } fun main() { // SAM conversion: lambda no lugar da interface val resultado = aplicar(5) { it * 3 } println(resultado) // 15 } Casos de Uso no Mundo Real Processamento de coleções: lambdas são usadas em praticamente toda operação com listas, maps e sets no Kotlin — filter, map, reduce, groupBy, sortedBy e dezenas de outros operadores recebem lambdas. Callbacks em aplicações Android: listeners de clique, observadores de LiveData e callbacks de animação são substituídos por lambdas concisas no lugar de classes anônimas verbosas do Java. Configuração de objetos com scope functions: apply { }, also { } e let { } usam lambdas para configurar objetos de forma fluente e legível. DSLs type-safe: lambdas com receiver permitem criar APIs como o HTML DSL do Kotlin (html { body { p { +\u0026quot;texto\u0026quot; } } }) e as definições de rotas do Ktor. Boas Práticas Use it apenas quando a lambda é curta e o significado do parâmetro é óbvio. Em lambdas mais longas, dê um nome descritivo ao parâmetro. Prefira trailing lambda syntax quando a lambda é o último ou único argumento. Isso é o padrão idiomático em Kotlin. Evite lambdas com mais de 5-7 linhas. Se a lógica é complexa, extraia para uma função nomeada e passe como referência com ::. Use destructuring declarations em lambdas quando trabalhar com pares ou data classes: map.forEach { (chave, valor) -\u0026gt; ... }. Prefira fun interface em Kotlin quando precisar de SAM conversion para interfaces Kotlin, em vez de usar tipos de função diretamente. Erros Comuns Confundir return em lambda e em função anônima: em lambdas inline, return sai da função envolvente. Use return@nomeDaFuncao para retornar apenas da lambda. Em funções anônimas, return sempre retorna da função anônima. Usar it em lambdas aninhadas: quando há lambdas dentro de lambdas, it se refere ao parâmetro da lambda mais interna. Isso causa confusão. Nomeie os parâmetros explicitamente. Capturar variáveis mutáveis inadvertidamente: lambdas que capturam variáveis var podem gerar bugs quando executadas de forma assíncrona, pois o valor da variável pode mudar entre a criação da lambda e sua execução. Esquecer que lambdas criam objetos: cada lambda não-inline cria um objeto na JVM. Em loops de alta frequência, isso pode causar pressão no garbage collector. Use inline na função receptora para evitar. Não aproveitar a desestruturação: escrever { par -\u0026gt; par.first } em vez de { (primeiro, _) -\u0026gt; primeiro } torna o código menos legível quando se trabalha com pares ou data classes. Perguntas Frequentes Qual a diferença entre lambda e higher-order function? Uma lambda é uma função anônima que pode ser tratada como valor. Uma higher-order function é uma função que recebe ou retorna outras funções (incluindo lambdas). São conceitos complementares.\nLambdas afetam a performance? Sem o modificador inline na função receptora, cada lambda cria um objeto Function na JVM. Para a maioria dos casos, o impacto é desprezível. Em hot paths, use funções inline para eliminar essa alocação.\nPosso usar lambdas com coroutines? Sim. Lambdas suspensas (do tipo suspend () -\u0026gt; T) são usadas extensivamente em coroutines. Funções como launch, async e withContext recebem lambdas suspensas como parâmetro.\nQuando devo usar função anônima em vez de lambda? Use função anônima quando precisar de um return que retorne apenas da própria função e não da função envolvente, ou quando quiser declarar o tipo de retorno explicitamente. Na maioria dos casos, lambdas são a escolha preferida.\nTermos Relacionados Higher-Order Function — funções que recebem ou retornam lambdas Fun — palavra-chave para declarar funções nomeadas, em contraste com lambdas (anônimas) Inline — modificador que elimina o overhead de alocação de objetos para lambdas Flow — API de streams assíncronos que utiliza lambdas em seus operadores Lambdas estão por toda parte no Kotlin. Dominar essa sintaxe é essencial pra escrever código idiomático e produtivo.\n","permalink":"https://kotlin.dev.br/glossario/lambda/","summary":"\u003ch2 id=\"o-que-é-lambda-em-kotlin\"\u003eO que é Lambda em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUma \u003cstrong\u003elambda\u003c/strong\u003e é uma função anônima — uma função sem nome que pode ser tratada como valor. Você pode armazená-la em variáveis, passá-la como argumento ou retorná-la de outra função. Lambdas são a base da programação funcional em Kotlin.\u003c/p\u003e\n\u003cp\u003eA sintaxe é simples: tudo fica entre chaves \u003ccode\u003e{}\u003c/code\u003e, com os parâmetros antes da seta \u003ccode\u003e-\u0026gt;\u003c/code\u003e é o corpo depois.\u003c/p\u003e\n\u003ch3 id=\"sintaxe-básica\"\u003eSintaxe básica\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003esaudacao\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"n\"\u003enome\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Olá, \u003c/span\u003e\u003cspan class=\"si\"\u003e$nome\u003c/span\u003e\u003cspan class=\"s2\"\u003e!\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esaudacao\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Karina\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e  \u003cspan class=\"c1\"\u003e// Olá, Karina!\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"lambda-como-argumento\"\u003eLambda como argumento\u003c/h3\u003e\n\u003cp\u003eO uso mais comum de lambdas é como argumento de funções, especialmente com coleções:\u003c/p\u003e","title":"Lambda em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é async em Kotlin? O async é um coroutine builder que inicia uma coroutine e retorna um Deferred\u0026lt;T\u0026gt; \u0026ndash; uma promessa de que um resultado vai estar disponivel no futuro. Para obter o valor, você chama await().\nEnquanto launch e \u0026ldquo;dispara e esquece\u0026rdquo;, async e \u0026ldquo;dispara e pega o resultado depois\u0026rdquo;. E a ferramenta certa quando você precisa executar tarefas em paralelo e combinar os resultados.\nImagine que você esta num restaurante e pede um prato principal é uma sobremesa. Em vez de esperar o prato principal ficar pronto para só entao pedir a sobremesa, você faz os dois pedidos de uma vez. A cozinha prepara ambos em paralelo e você recebe tudo mais rápido. E exatamente assim que o async funciona: dispara várias tarefas simultaneamente e coleta os resultados quando estao prontos.\nExemplo básico import kotlinx.coroutines.* suspend fun buscarPreco(): Double { delay(1000) return 49.90 } suspend fun buscarEstoque(): Int { delay(1000) return 150 } fun main() = runBlocking { val inicio = System.currentTimeMillis() val preco = async { buscarPreco() } val estoque = async { buscarEstoque() } println(\u0026#34;Preco: R$ ${preco.await()}\u0026#34;) println(\u0026#34;Estoque: ${estoque.await()} unidades\u0026#34;) println(\u0026#34;Tempo: ${System.currentTimeMillis() - inicio}ms\u0026#34;) // Tempo: ~1000ms (paralelo, nao 2000ms) } As duas chamadas rodam ao mesmo tempo. Se fossem sequenciais, levaria 2 segundos. Com async, leva apenas 1.\nDeferred e como um Future O Deferred funciona de maneira parecida com Future ou Promise de outras linguagens. Ele representa um valor que ainda esta sendo calculado.\nval resultado: Deferred\u0026lt;String\u0026gt; = async { delay(500) \u0026#34;Pronto!\u0026#34; } // Faz outras coisas enquanto espera... println(resultado.await()) // Bloqueia so aqui se ainda nao terminou Cuidado com async desnecessário Um erro comum e usar async seguido de await imediatamente, o que não da nenhum ganho:\n// Ruim -- e o mesmo que chamar a funcao diretamente val resultado = async { buscarPreco() }.await() // Bom -- executa em paralelo com outra tarefa val a = async { buscarPreco() } val b = async { buscarEstoque() } println(\u0026#34;${a.await()} - ${b.await()}\u0026#34;) Tratamento de erros Se uma exceção acontece dentro do async, ela e propagada quando você chama await():\nval resultado = async { throw RuntimeException(\u0026#34;Deu ruim!\u0026#34;) } try { resultado.await() } catch (e: Exception) { println(\u0026#34;Erro: ${e.message}\u0026#34;) } Carregamento paralelo de dados de API Um cenário muito comum e carregar dados de múltiplas fontes simultaneamente para montar uma tela ou resposta:\nimport kotlinx.coroutines.* data class PerfilUsuario(val nome: String, val pedidos: List\u0026lt;String\u0026gt;, val pontos: Int) suspend fun buscarNome(userId: String): String { delay(800) // simula chamada de rede return \u0026#34;Maria Silva\u0026#34; } suspend fun buscarPedidos(userId: String): List\u0026lt;String\u0026gt; { delay(1200) return listOf(\u0026#34;Pedido #101\u0026#34;, \u0026#34;Pedido #102\u0026#34;, \u0026#34;Pedido #103\u0026#34;) } suspend fun buscarPontos(userId: String): Int { delay(600) return 4500 } suspend fun carregarPerfil(userId: String): PerfilUsuario = coroutineScope { val nome = async { buscarNome(userId) } val pedidos = async { buscarPedidos(userId) } val pontos = async { buscarPontos(userId) } PerfilUsuario( nome = nome.await(), pedidos = pedidos.await(), pontos = pontos.await() ) // Tempo total: ~1200ms (o mais lento), nao 2600ms } Async com tratamento robusto de falhas Quando uma das tarefas paralelas pode falhar, use supervisorScope para evitar que todas as outras sejam canceladas:\nimport kotlinx.coroutines.* suspend fun carregarDadosComFallback() = supervisorScope { val principal = async { // pode falhar buscarPreco() } val reserva = async { delay(500) 39.90 // preco de fallback } try { principal.await() } catch (e: Exception) { println(\u0026#34;Fonte principal falhou, usando reserva\u0026#34;) reserva.await() } } Processamento em lote com async Quando você precisa processar uma lista de itens em paralelo:\nimport kotlinx.coroutines.* suspend fun processarItem(id: Int): String { delay(500) return \u0026#34;Resultado do item $id\u0026#34; } fun main() = runBlocking { val ids = (1..10).toList() val resultados = ids.map { id -\u0026gt; async { processarItem(id) } }.awaitAll() resultados.forEach { println(it) } // Todos os 10 itens processados em ~500ms, nao 5000ms } Casos de Uso no Mundo Real Telas de aplicativos: carregar dados do usuário, notificacoes e recomendacoes em paralelo para montar uma tela inicial rapidamente. Agregacao de microsservicos: um servico de backend chama vários outros servicos simultaneamente e combina as respostas em um único objeto. Processamento de imagens: redimensionar, aplicar filtros e gerar thumbnails de uma imagem ao mesmo tempo. Validacao paralela: verificar disponibilidade de username, validar email e consultar CEP simultaneamente durante um cadastro. Boas Praticas Sempre use coroutineScope ou supervisorScope para estruturar suas chamadas async, garantindo que falhas sejam tratadas corretamente. Use awaitAll() quando tiver uma colecao de Deferred, em vez de chamar await() individualmente em cada um. Escolha o Dispatcher adequado: Dispatchers.IO para operações de rede ou disco, Dispatchers.Default para processamento pesado de CPU. Evite async dentro de GlobalScope, pois você perde o controle do ciclo de vida da coroutine. Considere usar Flow quando os dados chegam como um stream continuo em vez de um resultado único. Erros Comuns async + await imediato: async { tarefa() }.await() e equivalente a chamar tarefa() diretamente. O async só faz sentido quando você dispara múltiplas tarefas antes de chamar await. Ignorar exceções: se você nunca chama await() em um Deferred que falhou, a exceção pode ser engolida silenciosamente, dificultando a depuração. Criar coroutines demais: disparar milhares de async sem limitar a concorrencia pode sobrecarregar recursos. Use Semaphore ou processe em lotes. Esquecer a concorrencia estruturada: usar GlobalScope.async em vez de coroutineScope pode causar vazamento de coroutines se o escopo pai for cancelado. Perguntas Frequentes Qual a diferenca entre async e launch? launch retorna um Job e e usado quando você não precisa de um resultado (fire-and-forget). async retorna um Deferred\u0026lt;T\u0026gt; e e usado quando você precisa do resultado da computacao.\nPosso usar async sem await? Tecnicamente sim, mas a coroutine vai executar sem que você colete o resultado. Se ocorrer uma exceção, ela pode ser perdida. Sempre chame await() ou use awaitAll().\nasync roda em outra thread? Depende do Dispatcher. Por padrão, async herda o dispatcher do escopo pai. Se você usar async(Dispatchers.IO), ele executara em uma thread do pool de IO.\nQuando devo usar async vs Channel? Use async para tarefas que produzem um resultado único. Use Channel para comunicação continua entre coroutines, onde dados sao enviados e recebidos ao longo do tempo.\n","permalink":"https://kotlin.dev.br/glossario/async/","summary":"\u003ch2 id=\"o-que-é-async-em-kotlin\"\u003eO que é \u003ccode\u003easync\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO \u003ccode\u003easync\u003c/code\u003e é um \u003cstrong\u003ecoroutine builder\u003c/strong\u003e que inicia uma \u003ca href=\"/glossario/coroutine/\"\u003ecoroutine\u003c/a\u003e e retorna um \u003ccode\u003eDeferred\u0026lt;T\u0026gt;\u003c/code\u003e \u0026ndash; uma promessa de que um resultado vai estar disponivel no futuro. Para obter o valor, você chama \u003ccode\u003eawait()\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eEnquanto \u003ca href=\"/glossario/launch/\"\u003elaunch\u003c/a\u003e e \u0026ldquo;dispara e esquece\u0026rdquo;, \u003ccode\u003easync\u003c/code\u003e e \u0026ldquo;dispara e pega o resultado depois\u0026rdquo;. E a ferramenta certa quando você precisa executar tarefas em paralelo e combinar os resultados.\u003c/p\u003e\n\u003cp\u003eImagine que você esta num restaurante e pede um prato principal é uma sobremesa. Em vez de esperar o prato principal ficar pronto para só entao pedir a sobremesa, você faz os dois pedidos de uma vez. A cozinha prepara ambos em paralelo e você recebe tudo mais rápido. E exatamente assim que o \u003ccode\u003easync\u003c/code\u003e funciona: dispara várias tarefas simultaneamente e coleta os resultados quando estao prontos.\u003c/p\u003e","title":"Async em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Nullable em Kotlin? Em Kotlin, todo tipo é não-nulo por padrão. Se você declara uma variável como String, ela não pode receber null. Para permitir valores nulos, você precisa adicionar ? ao tipo, criando um tipo nullable como String?.\nEssa é uma das maiores sacadas do Kotlin: o famoso NullPointerException é praticamente eliminado em tempo de compilação.\nDeclarando tipos nullable var nome: String = \u0026#34;Karina\u0026#34; // nome = null // Erro de compilacao! var apelido: String? = \u0026#34;Kah\u0026#34; apelido = null // Tudo certo! Operador de chamada segura ?. O operador ?. só executa a operação se o valor não for nulo:\nval cidade: String? = \u0026#34;São Paulo\u0026#34; println(cidade?.length) // 9 val estado: String? = null println(estado?.length) // null (nao dá erro!) Operador Elvis ?: O operador Elvis fornece um valor padrão quando o original é nulo:\nval nome: String? = null val exibicao = nome ?: \u0026#34;Anônimo\u0026#34; println(exibicao) // Anônimo Combina muito bem com o operador ?.:\nfun tamanhoDoNome(nome: String?): Int { return nome?.length ?: 0 } println(tamanhoDoNome(\u0026#34;Fernanda\u0026#34;)) // 8 println(tamanhoDoNome(null)) // 0 Operador de asserção !! O !! força a conversão para não-nulo, mas lança exceção se o valor for null:\nval valor: String? = \u0026#34;Kotlin\u0026#34; println(valor!!.length) // 6 val nulo: String? = null // println(nulo!!.length) // NullPointerException! Use !! com muito cuidado — só quando você tem certeza absoluta de que o valor não é nulo.\nSmart cast com if O Kotlin faz smart cast automaticamente após verificações de null:\nfun imprimir(texto: String?) { if (texto != null) { // Aqui o compilador já sabe que texto nao é null println(texto.uppercase()) } } Encadeamento seguro com let A função let combinada com ?. é uma das formas mais elegantes de trabalhar com nullable:\ndata class Endereco(val rua: String?, val cidade: String?) data class Usuario(val nome: String, val endereco: Endereco?) fun exibirCidade(usuario: Usuario) { usuario.endereco?.cidade?.let { cidade -\u0026gt; println(\u0026#34;O usuário mora em $cidade\u0026#34;) } ?: println(\u0026#34;Cidade nao informada\u0026#34;) } fun main() { val usuario1 = Usuario(\u0026#34;Ana\u0026#34;, Endereco(\u0026#34;Rua A\u0026#34;, \u0026#34;Curitiba\u0026#34;)) val usuario2 = Usuario(\u0026#34;Pedro\u0026#34;, null) exibirCidade(usuario1) // O usuário mora em Curitiba exibirCidade(usuario2) // Cidade nao informada } Coleções e Nullable Kotlin diferencia entre coleções que podem conter elementos nulos e coleções que podem ser nulas:\n// Lista que pode conter elementos nulos val nomes: List\u0026lt;String?\u0026gt; = listOf(\u0026#34;Ana\u0026#34;, null, \u0026#34;Carlos\u0026#34;, null) val naoNulos = nomes.filterNotNull() println(naoNulos) // [Ana, Carlos] // Lista que pode ser nula val lista: List\u0026lt;String\u0026gt;? = null println(lista?.size ?: 0) // 0 // Lista que pode ser nula E conter elementos nulos val mista: List\u0026lt;String?\u0026gt;? = listOf(\u0026#34;Kotlin\u0026#34;, null, \u0026#34;Brasil\u0026#34;) val resultado = mista?.filterNotNull()?.joinToString() println(resultado) // Kotlin, Brasil Casos de Uso no Mundo Real Dados vindos de APIs externas: respostas JSON frequentemente contêm campos opcionais. Usar tipos nullable permite modelar esses campos de forma segura sem arriscar crashes em tempo de execução. Formulários de cadastro: campos não obrigatórios como apelido, telefone secundário ou foto de perfil são naturalmente nullable na modelagem do domínio. Integração com código Java: bibliotecas Java podem retornar null em qualquer lugar. Os tipos nullable do Kotlin servem como camada de proteção nessa integração. Busca em banco de dados: consultas que podem não encontrar resultados retornam null naturalmente, como findById() que retorna Usuario?. Boas Práticas Prefira ?. e ?: em vez de !!. O operador !! deve ser a exceção, não a regra. Use let para trabalhar com nullable: valor?.let { println(it) }. Evite tipos nullable quando possível — menos ?, menos problemas. Se um valor sempre vai existir, declare como não-nulo. Valide valores nullable nas bordas do sistema (entrada de dados, respostas de API) e converta para tipos não-nulos o mais cedo possível. Use requireNotNull() ou checkNotNull() para válidações explícitas com mensagens de erro descritivas, em vez de !!. Erros Comuns Usar !! em toda parte: isso destrói a segurança contra nulos do Kotlin. Cada !! é um potencial NullPointerException esperando para acontecer. Ignorar avisos do compilador sobre platform types: quando você usa código Java, o Kotlin mostra tipos como String! (platform type). Sempre trate esses tipos como nullable para evitar surpresas. Criar cadeias longas de ?.: encadeamentos como a?.b?.c?.d?.e indicam que o modelo de dados pode estar mal estruturado. Considere refatorar. Usar nullable para valores com default: se um campo sempre tem um valor padrão, use esse valor em vez de null. Por exemplo, val nome: String = \u0026quot;\u0026quot; é melhor que val nome: String? = null quando string vazia é aceitável. Esquecer de tratar o caso null: usar apenas ?. sem ?: pode resultar em null silencioso propagando pelo sistema sem que ninguém perceba. Perguntas Frequentes Qual a diferença entre String e String? em Kotlin? String é um tipo não-nulo que nunca pode receber null. String? é o tipo nullable equivalente, que aceita tanto valores de texto quanto null. O compilador trata os dois como tipos diferentes e exige operadores seguros ao trabalhar com String?.\nQuando devo usar !! em vez de ?.? Praticamente nunca. O !! deve ser usado apenas quando você tem garantia lógica absoluta de que o valor não é nulo e quer que o programa falhe caso esteja errado. Prefira requireNotNull() que permite incluir uma mensagem de erro explicativa.\nO Kotlin elimina completamente o NullPointerException? Não completamente, mas reduz drasticamente. NPEs ainda podem ocorrer ao usar !!, ao interagir com código Java, ou em cenários de concorrência. A diferença é que, no Kotlin, quase todo NPE é uma escolha consciente do desenvolvedor.\nComo lidar com nullable em interoperabilidade com Java? Trate todos os tipos vindos de Java como nullable por padrão, a menos que a biblioteca Java use anotações como @NotNull ou @Nullable. Use ?. e ?: para criar uma camada de segurança entre o código Kotlin e o Java.\nTermos Relacionados Data Class — classes de dados que frequentemente contêm propriedades nullable Scope Functions — let, run e outras funções úteis para trabalhar com nullable Smart Cast — conversão automática de tipos após verificações de null Extension Function — funções de extensão que podem ser declaradas para tipos nullable ","permalink":"https://kotlin.dev.br/glossario/nullable/","summary":"\u003ch2 id=\"o-que-é-nullable-em-kotlin\"\u003eO que é Nullable em Kotlin?\u003c/h2\u003e\n\u003cp\u003eEm Kotlin, \u003cstrong\u003etodo tipo é não-nulo por padrão\u003c/strong\u003e. Se você declara uma variável como \u003ccode\u003eString\u003c/code\u003e, ela não pode receber \u003ccode\u003enull\u003c/code\u003e. Para permitir valores nulos, você precisa adicionar \u003ccode\u003e?\u003c/code\u003e ao tipo, criando um tipo \u003cstrong\u003enullable\u003c/strong\u003e como \u003ccode\u003eString?\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eEssa é uma das maiores sacadas do Kotlin: o famoso \u003ccode\u003eNullPointerException\u003c/code\u003e é praticamente eliminado em tempo de compilação.\u003c/p\u003e\n\u003ch3 id=\"declarando-tipos-nullable\"\u003eDeclarando tipos nullable\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003evar\u003c/span\u003e \u003cspan class=\"py\"\u003enome\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Karina\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// nome = null  // Erro de compilacao!\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003evar\u003c/span\u003e \u003cspan class=\"py\"\u003eapelido\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e?\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Kah\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eapelido\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003enull\u003c/span\u003e  \u003cspan class=\"c1\"\u003e// Tudo certo!\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"operador-de-chamada-segura-\"\u003eOperador de chamada segura \u003ccode\u003e?.\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003eO operador \u003ccode\u003e?.\u003c/code\u003e só executa a operação se o valor não for nulo:\u003c/p\u003e","title":"Nullable em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é launch em Kotlin? O launch é um coroutine builder que inicia uma nova coroutine sem retornar resultado. Ele é do tipo \u0026ldquo;fire-and-forget\u0026rdquo; — você dispara a coroutine e segue em frente. Perfeito pra tarefas que precisam rodar em background mas não precisam devolver um valor.\nO launch retorna um Job, que permite controlar o ciclo de vida da coroutine: cancelar, esperar terminar ou verificar o status.\nExemplo básico import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { println(\u0026#34;Coroutine iniciada\u0026#34;) delay(1000) println(\u0026#34;Coroutine finalizada\u0026#34;) } println(\u0026#34;Código principal continua...\u0026#34;) job.join() // Espera a coroutine terminar } Saída:\nCódigo principal continua... Coroutine iniciada Coroutine finalizada Controlando com Job O Job retornado pelo launch oferece várias possibilidades:\nimport kotlinx.coroutines.* fun main() = runBlocking { val job = launch { repeat(100) { i -\u0026gt; println(\u0026#34;Processando item $i\u0026#34;) delay(200) } } delay(1000) println(\u0026#34;Cansou de esperar!\u0026#34;) job.cancel() println(\u0026#34;Job cancelado: ${job.isCancelled}\u0026#34;) } Dispatchers Você pode escolher em qual thread a coroutine vai rodar:\nimport kotlinx.coroutines.* fun main() = runBlocking { launch(Dispatchers.Default) { println(\u0026#34;CPU-intensivo em: ${Thread.currentThread().name}\u0026#34;) } launch(Dispatchers.IO) { println(\u0026#34;Operação de I/O em: ${Thread.currentThread().name}\u0026#34;) } } Dispatchers.Default — tarefas pesadas de CPU Dispatchers.IO — operações de entrada/saída Dispatchers.Main — thread principal (Android) launch vs async A diferença é simples: launch não retorna valor, async retorna. Se você precisa do resultado da coroutine, use async. Se é só pra executar algo no background, launch resolve.\n// Não precisa do resultado? Use launch launch { salvarNoLog(\u0026#34;evento_123\u0026#34;) } // Precisa do resultado? Use async val dados = async { buscarDados() } println(dados.await()) Structured Concurrency com launch O launch respeita o conceito de structured concurrency do Kotlin. Isso significa que uma coroutine filha está vinculada ao escopo pai. Se o escopo pai for cancelado, todas as coroutines filhas também são canceladas automaticamente.\nimport kotlinx.coroutines.* fun main() = runBlocking { val escopo = CoroutineScope(Dispatchers.Default) val jobPai = escopo.launch { launch { delay(2000) println(\u0026#34;Filha 1 terminou\u0026#34;) // Nunca será impresso } launch { delay(2000) println(\u0026#34;Filha 2 terminou\u0026#34;) // Nunca será impresso } } delay(500) jobPai.cancel() // Cancela o pai e todas as filhas println(\u0026#34;Todas as coroutines foram canceladas\u0026#34;) } Tratamento de exceções com launch Diferente do async, onde exceções são lançadas ao chamar await(), no launch as exceções propagam imediatamente para o escopo pai. Para interceptá-las, use um CoroutineExceptionHandler:\nimport kotlinx.coroutines.* fun main() = runBlocking { val handler = CoroutineExceptionHandler { _, excecao -\u0026gt; println(\u0026#34;Exceção capturada: ${excecao.message}\u0026#34;) } val escopo = CoroutineScope(Dispatchers.Default + handler) escopo.launch { throw RuntimeException(\u0026#34;Algo deu errado!\u0026#34;) } delay(500) // Aguarda para ver a saída } Casos de Uso no Mundo Real Envio de analytics e telemetria: disparar eventos de rastreamento sem bloquear a interface do usuário. O resultado do envio não importa para o fluxo principal da aplicação. Sincronização periódica de dados: usar launch dentro de um loop com delay para sincronizar dados com o servidor a cada intervalo de tempo, como atualizar cache local. Processamento de filas: consumir itens de uma fila (mensagens, notificações, tarefas) em background, processando cada item de forma independente sem precisar do resultado. Atualização de UI no Android: disparar operações de atualização de tela a partir do viewModelScope.launch, garantindo que a coroutine seja cancelada automaticamente quando o ViewModel for destruído. Boas Práticas Sempre use launch dentro de um CoroutineScope bem definido. Evite usar GlobalScope.launch, pois ele não respeita o ciclo de vida da aplicação e pode causar vazamentos de memória. Prefira Dispatchers.IO para operações de rede e disco, e Dispatchers.Default para cálculos pesados. Nunca faça operações bloqueantes no Dispatchers.Main. Utilize job.join() quando precisar garantir que a coroutine terminou antes de prosseguir, mas evite usá-lo excessivamente — isso anula a vantagem da concorrência. Trate exceções com CoroutineExceptionHandler ou blocos try/catch dentro do launch para evitar crashes inesperados. Use supervisorScope quando quiser que a falha de uma coroutine filha não cancele as irmãs. Erros Comuns Usar GlobalScope.launch indiscriminadamente: isso cria coroutines que vivem durante toda a aplicação, podendo causar vazamentos de memória e comportamentos inesperados. Esquecer de cancelar coroutines: não vincular o launch a um escopo com ciclo de vida definido faz com que coroutines continuem rodando mesmo depois que a tela ou componente foi destruído. Ignorar exceções: como o launch propaga exceções para o escopo pai, não tratá-las pode derrubar toda a aplicação silenciosamente. Bloquear a thread dentro do launch: usar Thread.sleep() em vez de delay() bloqueia a thread e desperdiça os benefícios das coroutines. Confundir launch com async: tentar obter um resultado de launch não funciona. Se precisa de retorno, use async com await(). Perguntas Frequentes O launch bloqueia a thread? Não. O launch inicia a coroutine de forma assíncrona e retorna imediatamente um Job. A thread que chamou o launch continua executando o código seguinte sem esperar.\nQuando usar launch em vez de async? Use launch quando a tarefa não precisa devolver um resultado para quem a iniciou. Exemplos: salvar logs, enviar eventos de analytics, atualizar cache. Se precisa do valor de retorno, use async.\nO que acontece se uma exceção ocorrer dentro do launch? A exceção é propagada para o escopo pai. Se não houver tratamento, ela pode cancelar todo o escopo e suas coroutines filhas. Use CoroutineExceptionHandler ou try/catch interno para lidar com isso.\nPosso usar launch fora de um CoroutineScope? Não. O launch é uma função de extensão de CoroutineScope. Você precisa de um escopo como runBlocking, viewModelScope, lifecycleScope ou um CoroutineScope customizado.\nTermos Relacionados Coroutine — o conceito fundamental de concorrência leve em Kotlin Suspend — funções que podem ser pausadas e retomadas dentro de coroutines Async — coroutine builder que retorna um resultado via Deferred Flow — streams assíncronos reativos baseados em coroutines launch é provavelmente o coroutine builder que você mais vai usar no dia a dia.\n","permalink":"https://kotlin.dev.br/glossario/launch/","summary":"\u003ch2 id=\"o-que-é-launch-em-kotlin\"\u003eO que é \u003ccode\u003elaunch\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO \u003ccode\u003elaunch\u003c/code\u003e é um \u003cstrong\u003ecoroutine builder\u003c/strong\u003e que inicia uma nova coroutine sem retornar resultado. Ele é do tipo \u0026ldquo;fire-and-forget\u0026rdquo; — você dispara a coroutine e segue em frente. Perfeito pra tarefas que precisam rodar em background mas não precisam devolver um valor.\u003c/p\u003e\n\u003cp\u003eO \u003ccode\u003elaunch\u003c/code\u003e retorna um \u003ccode\u003eJob\u003c/code\u003e, que permite controlar o ciclo de vida da coroutine: cancelar, esperar terminar ou verificar o status.\u003c/p\u003e\n\u003ch3 id=\"exemplo-básico\"\u003eExemplo básico\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003ekotlinx.coroutines.*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erunBlocking\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003ejob\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003elaunch\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Coroutine iniciada\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003edelay\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1000\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Coroutine finalizada\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Código principal continua...\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ejob\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ejoin\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Espera a coroutine terminar\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eSaída:\u003c/p\u003e","title":"Launch em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que são Scope Functions em Kotlin? Scope Functions são cinco funções da biblioteca padrão do Kotlin — let, run, with, apply e also — que permitem executar um bloco de código no contexto de um objeto. Elas deixam o código mais conciso e expressivo.\nA diferença entre elas está em como o objeto é referenciado dentro do bloco (this ou it) e no que cada uma retorna.\nResumo rápido Função Referência Retorno let it Resultado do lambda run this Resultado do lambda with this Resultado do lambda apply this O próprio objeto also it O próprio objeto let — transformações e null safety val nome: String? = \u0026#34;Kotlin Brasil\u0026#34; nome?.let { println(\u0026#34;O nome tem ${it.length} caracteres\u0026#34;) } Perfeito pra trabalhar com valores nullable de forma segura.\napply — configurar objetos data class Servidor(var host: String = \u0026#34;\u0026#34;, var porta: Int = 0, var protocolo: String = \u0026#34;\u0026#34;) val servidor = Servidor().apply { host = \u0026#34;api.kotlin.dev.br\u0026#34; porta = 443 protocolo = \u0026#34;HTTPS\u0026#34; } println(servidor) O apply retorna o próprio objeto, ideal pra configurar e já usar em seguida.\nalso — ações laterais val numeros = mutableListOf(1, 2, 3) .also { println(\u0026#34;Lista original: $it\u0026#34;) } .also { it.add(4) } println(numeros) // [1, 2, 3, 4] Bom pra logging e debug sem quebrar a cadeia de chamadas.\nrun — calcular resultado val resultado = \u0026#34;Kotlin\u0026#34;.run { println(\u0026#34;Processando: $this\u0026#34;) length * 2 } println(resultado) // 12 with — operar sobre um objeto val sb = StringBuilder() val texto = with(sb) { append(\u0026#34;Olá, \u0026#34;) append(\u0026#34;mundo!\u0026#34;) toString() } println(texto) // Olá, mundo! Combinando scope functions Na prática, você frequentemente combina scope functions para criar código fluente e expressivo. Veja um exemplo de configuração de uma requisição HTTP:\ndata class Requisicao( var url: String = \u0026#34;\u0026#34;, var metodo: String = \u0026#34;GET\u0026#34;, var headers: MutableMap\u0026lt;String, String\u0026gt; = mutableMapOf(), var corpo: String? = null ) fun criarRequisicao(): Requisicao { return Requisicao().apply { url = \u0026#34;https://api.kotlin.dev.br/usuarios\u0026#34; metodo = \u0026#34;POST\u0026#34; headers[\u0026#34;Content-Type\u0026#34;] = \u0026#34;application/json\u0026#34; headers[\u0026#34;Authorization\u0026#34;] = \u0026#34;Bearer token123\u0026#34; corpo = \u0026#34;\u0026#34;\u0026#34;{\u0026#34;nome\u0026#34;: \u0026#34;Karina\u0026#34;}\u0026#34;\u0026#34;\u0026#34; }.also { println(\u0026#34;Requisição criada: ${it.metodo} ${it.url}\u0026#34;) } } run sem objeto — executando blocos O run também pode ser usado sem um objeto receptor, funcionando como um bloco de código que retorna um valor:\nval resultado = run { val a = 10 val b = 20 val c = 30 a + b + c } println(resultado) // 60 Isso é útil quando você precisa calcular um valor complexo em uma variável val, criando um escopo isolado para variáveis temporárias.\nlet para encadeamento de transformações O let brilha quando você precisa transformar um valor em cadeia:\nfun processarEntrada(entrada: String?): String { return entrada ?.let { it.trim() } ?.let { it.lowercase() } ?.let { it.replace(\u0026#34; \u0026#34;, \u0026#34;_\u0026#34;) } ?.let { \u0026#34;usuario_$it\u0026#34; } ?: \u0026#34;usuario_anonimo\u0026#34; } fun main() { println(processarEntrada(\u0026#34; Kotlin Brasil \u0026#34;)) // usuario_kotlin_brasil println(processarEntrada(null)) // usuario_anonimo } Qual usar? Na dúvida: apply pra configurar, let pra null safety, also pra ações laterais, run pra calcular algo e with quando já tem o objeto em mãos.\nCasos de Uso no Mundo Real Configuração de objetos complexos: usar apply para configurar ViewModels, clientes HTTP, builders de notificação e outros objetos com múltiplas propriedades no Android e backend. Null safety em respostas de API: usar let combinado com ?. para processar dados que podem ser nulos vindos de APIs REST ou banco de dados, evitando verificações manuais de null. Logging e debug em pipelines: inserir also no meio de cadeias de chamadas para imprimir valores intermediários sem alterar o fluxo de dados, facilitando a depuração. Inicialização de recursos com run: usar run para criar e configurar recursos como conexões de banco de dados, onde o resultado da configuração é o valor retornado. Boas Práticas Não aninhe scope functions. objeto.let { it.apply { also { } } } é ilegível. Limite-se a um nível de profundidade. Use apply para configuração e also para efeitos colaterais. Embora ambos retornem o próprio objeto, a distinção semântica mantém o código claro. Prefira let com nome explícito para lambdas longas: valor?.let { usuário -\u0026gt; ... } é mais legível que valor?.let { it.nome; it.email; ... } quando o bloco é grande. Use with apenas quando o objeto não é nullable. Como with não é uma função de extensão, ele não funciona com o operador ?.. Mantenha blocos de scope functions curtos — entre 3 e 7 linhas. Se o bloco crescer muito, extraia para uma função separada. Erros Comuns Aninhar scope functions excessivamente: a.let { it.run { this.apply { } } } cria código impossível de entender. Se precisa de mais de uma scope function, quebre em etapas. Confundir this e it: apply e run usam this (receptor implícito); let e also usam it (parâmetro explícito). Usar o errado gera confusão e erros de compilação. Usar let sem necessidade: valor.let { println(it) } não é melhor que println(valor). Use let quando há uma razão real, como null safety ou transformação. Ignorar o retorno: apply e also retornam o objeto; let, run e with retornam o resultado do lambda. Confundir isso leva a bugs sutis, especialmente em cadeias de chamadas. Usar with em objetos nullable: como with não é uma extensão, with(objetoNullable) compila mas pode dar NullPointerException. Para nullable, prefira objetoNullable?.run { }. Perguntas Frequentes Qual a diferença entre let e run? Ambos retornam o resultado do lambda. A diferença é que let referência o objeto como it (parâmetro), enquanto run referência como this (receptor). Use let quando precisar de um nome explícito para o objeto ou para null safety; use run quando quiser acessar propriedades e métodos diretamente.\nPosso substituir todas as scope functions por if/else e variáveis temporárias? Sim, scope functions são açúcar sintático. Mas elas tornam o código mais idiomático e expressivo. A comunidade Kotlin espera ver scope functions usadas nos contextos apropriados.\nScope functions afetam a performance? Na prática, não. As scope functions let, run, with, apply e also são todas inline, ou seja, não criam objetos lambda em tempo de execução. O compilador insere o código diretamente no ponto de chamada.\nQuando usar with em vez de run? Use with quando já tem o objeto em uma variável e quer operar sobre ele sem encadear. Use run quando quer encadear a chamada com ?. (null safety) ou quando o objeto é resultado de outra expressão.\nTermos Relacionados Lambda — expressões lambda que formam o bloco de código das scope functions Extension Function — let, run, apply e also são funções de extensão Nullable — scope functions como let são fundamentais para null safety Inline Function — scope functions são inline, sem overhead de runtime Higher-Order Function — scope functions são funções de ordem superior ","permalink":"https://kotlin.dev.br/glossario/scope/","summary":"\u003ch2 id=\"o-que-são-scope-functions-em-kotlin\"\u003eO que são Scope Functions em Kotlin?\u003c/h2\u003e\n\u003cp\u003eScope Functions são cinco funções da biblioteca padrão do Kotlin — \u003ccode\u003elet\u003c/code\u003e, \u003ccode\u003erun\u003c/code\u003e, \u003ccode\u003ewith\u003c/code\u003e, \u003ccode\u003eapply\u003c/code\u003e e \u003ccode\u003ealso\u003c/code\u003e — que permitem executar um bloco de código \u003cstrong\u003eno contexto de um objeto\u003c/strong\u003e. Elas deixam o código mais conciso e expressivo.\u003c/p\u003e\n\u003cp\u003eA diferença entre elas está em como o objeto é referenciado dentro do bloco (\u003ccode\u003ethis\u003c/code\u003e ou \u003ccode\u003eit\u003c/code\u003e) e no que cada uma retorna.\u003c/p\u003e\n\u003ch3 id=\"resumo-rápido\"\u003eResumo rápido\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eFunção\u003c/th\u003e\n          \u003cth\u003eReferência\u003c/th\u003e\n          \u003cth\u003eRetorno\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003elet\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eit\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eResultado do lambda\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003erun\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ethis\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eResultado do lambda\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003ewith\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ethis\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eResultado do lambda\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eapply\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ethis\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eO próprio objeto\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003ealso\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eit\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eO próprio objeto\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"let--transformações-e-null-safety\"\u003e\u003ccode\u003elet\u003c/code\u003e — transformações e null safety\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003enome\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e?\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Kotlin Brasil\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003enome\u003c/span\u003e\u003cspan class=\"o\"\u003e?.\u003c/span\u003e\u003cspan class=\"n\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;O nome tem \u003c/span\u003e\u003cspan class=\"si\"\u003e${it.length}\u003c/span\u003e\u003cspan class=\"s2\"\u003e caracteres\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003ePerfeito pra trabalhar com valores nullable de forma segura.\u003c/p\u003e","title":"Scope Functions em Kotlin: O que São e Como Usar | Kotlin Brasil"},{"content":"O que é Channel em Kotlin? Um Channel em Kotlin é uma estrutura para comunicação entre coroutines. Funciona como uma fila: uma coroutine envia dados pelo canal e outra recebe do outro lado. E o jeito mais seguro de trocar informações entre coroutines sem problemas de concorrencia. O conceito foi diretamente inspirado pelos channels de Go — a implementação em Kotlin segue padrões similares, mas adaptados para o ecossistema de coroutines da JVM.\nSe o Flow e como uma torneira (um produtor, um consumidor), o Channel é mais como um cano de comunicação bidirecional entre partes independentes do código.\nImagine uma esteira de fabrica: de um lado, um operario coloca pecas na esteira (send), e do outro lado, outro operario retira as pecas para montar o produto (receive). A esteira tem uma capacidade limitada \u0026ndash; se estiver cheia, o primeiro operario espera; se estiver vazia, o segundo espera. E exatamente assim que um Channel funciona.\nExemplo básico import kotlinx.coroutines.* import kotlinx.coroutines.channels.* fun main() = runBlocking { val canal = Channel\u0026lt;String\u0026gt;() launch { canal.send(\u0026#34;Primeira mensagem\u0026#34;) canal.send(\u0026#34;Segunda mensagem\u0026#34;) canal.close() } for (msg in canal) { println(\u0026#34;Recebido: $msg\u0026#34;) } } O send envia dados para o canal e o for consome. Quando o canal e fechado com close(), o loop encerra automaticamente.\nTipos de Channel Kotlin oferece diferentes capacidades de buffer:\n// Sem buffer -- send suspende ate alguem fazer receive val rendezvous = Channel\u0026lt;Int\u0026gt;() // Buffer limitado val buffered = Channel\u0026lt;Int\u0026gt;(capacity = 10) // Buffer ilimitado val unlimited = Channel\u0026lt;Int\u0026gt;(Channel.UNLIMITED) // Mantem so o ultimo valor val conflated = Channel\u0026lt;Int\u0026gt;(Channel.CONFLATED) Produtor e consumidor O padrão produtor-consumidor fica bem elegante com produce:\nimport kotlinx.coroutines.* import kotlinx.coroutines.channels.* fun CoroutineScope.produzirNumeros() = produce { for (i in 1..5) { delay(300) send(i) } } fun main() = runBlocking { val numeros = produzirNumeros() for (n in numeros) { println(\u0026#34;Numero: $n\u0026#34;) } } Channel vs Flow A principal diferenca e que Channel e hot \u0026ndash; ele produz dados independente de ter alguem consumindo. Ja o Flow e cold \u0026ndash; só produz quando alguem coleta.\nCaracteristica Channel Flow Tipo Hot Cold Produtores Um ou vários Um Consumidores Um Um ou vários Use Channel quando precisar de comunicação ativa entre coroutines. Para streams de dados reativos, prefira Flow.\nPipeline com Channels Channels permitem criar pipelines onde cada estagio processa dados e passa para o proximo, similar a um fluxo de producao industrial:\nimport kotlinx.coroutines.* import kotlinx.coroutines.channels.* fun CoroutineScope.gerarPedidos() = produce { val pedidos = listOf(\u0026#34;Pedido-001\u0026#34;, \u0026#34;Pedido-002\u0026#34;, \u0026#34;Pedido-003\u0026#34;, \u0026#34;Pedido-004\u0026#34;) for (pedido in pedidos) { delay(200) send(pedido) } } fun CoroutineScope.validarPedidos(entrada: ReceiveChannel\u0026lt;String\u0026gt;) = produce { for (pedido in entrada) { delay(150) send(\u0026#34;$pedido [VALIDADO]\u0026#34;) } } fun CoroutineScope.processarPagamento(entrada: ReceiveChannel\u0026lt;String\u0026gt;) = produce { for (pedido in entrada) { delay(300) send(\u0026#34;$pedido [PAGO]\u0026#34;) } } fun main() = runBlocking { val pedidos = gerarPedidos() val validados = validarPedidos(pedidos) val pagos = processarPagamento(validados) for (resultado in pagos) { println(resultado) } } Fan-out: múltiplos consumidores Quando você tem trabalho pesado, pode distribuir itens de um canal entre várias coroutines trabalhadoras:\nimport kotlinx.coroutines.* import kotlinx.coroutines.channels.* fun main() = runBlocking { val tarefas = Channel\u0026lt;Int\u0026gt;(capacity = 10) // Produtor: envia 20 tarefas launch { for (i in 1..20) { tarefas.send(i) } tarefas.close() } // 3 consumidores processando em paralelo repeat(3) { trabalhadorId -\u0026gt; launch { for (tarefa in tarefas) { delay(200) // simula processamento println(\u0026#34;Trabalhador $trabalhadorId processou tarefa $tarefa\u0026#34;) } } } } Fan-in: múltiplos produtores O cenário inverso também e comum \u0026ndash; vários produtores enviando para um único canal:\nimport kotlinx.coroutines.* import kotlinx.coroutines.channels.* suspend fun produzirLogs(canal: SendChannel\u0026lt;String\u0026gt;, origem: String, quantidade: Int) { repeat(quantidade) { i -\u0026gt; delay(100) canal.send(\u0026#34;[$origem] Log #$i\u0026#34;) } } fun main() = runBlocking { val logs = Channel\u0026lt;String\u0026gt;(Channel.UNLIMITED) launch { produzirLogs(logs, \u0026#34;SERVIDOR-A\u0026#34;, 3) } launch { produzirLogs(logs, \u0026#34;SERVIDOR-B\u0026#34;, 3) } launch { produzirLogs(logs, \u0026#34;SERVIDOR-C\u0026#34;, 3) } // Aguarda e depois fecha launch { delay(500) logs.close() } for (log in logs) { println(log) } } Casos de Uso no Mundo Real Filas de processamento: sistemas que recebem eventos (cliques, logs, transacoes) e os processam de forma assíncrona usando channels como fila intermediaria. Web scraping paralelo: um produtor gera URLs para visitar e múltiplos consumidores fazem as requisicoes em paralelo, reportando resultados em outro channel. Chat em tempo real: mensagens enviadas por usuários sao colocadas em um channel e distribuidas para todos os participantes da sala. Processamento de arquivos: leitura de linhas de um arquivo grande em um channel, com múltiplos trabalhadores processando cada linha em paralelo. Boas Praticas Sempre feche o channel com close() quando o produtor terminar, para que consumidores saibam que não havera mais dados. Prefira produce em vez de criar channels manualmente, pois ele garante o fechamento automatico e trata cancelamento corretamente. Use buffer limitado na maioria dos casos. Channel.UNLIMITED pode causar problemas de memória se o produtor for mais rápido que o consumidor. Use Channel.CONFLATED quando você só se importa com o valor mais recente, como atualizações de posicao GPS. Considere Flow antes de Channel. Muitas vezes um Flow resolve o problema de forma mais simples e com menos risco de vazamento de recursos. Erros Comuns Esquecer de fechar o channel: se o produtor não chama close(), o consumidor ficara suspenso para sempre esperando mais dados, causando travamento. Enviar para um channel fechado: chamar send() apos close() lanca ClosedSendChannelException. Verifique o estado antes ou use trySend(). Usar Channel quando Flow resolve: Channel e mais complexo e exige gerenciamento manual de ciclo de vida. Se você só precisa de um stream de dados cold, use Flow. Ignorar cancelamento: quando uma coroutine consumidora e cancelada, o channel pode ficar com dados não processados. Estruture o código com coroutineScope para garantir limpeza adequada. Perguntas Frequentes Qual a diferenca entre Channel e Flow? Channel e hot (produz dados independente de consumidores) e suporta múltiplos produtores. Flow e cold (só produz quando coletado) e e mais simples de usar. Prefira Flow para streams reativos e Channel para comunicação ativa entre coroutines.\nPosso ter vários consumidores no mesmo Channel? Sim, mas cada item sera recebido por apenas um consumidor (fan-out). Se você precisa que todos os consumidores recebam todos os itens, use BroadcastChannel ou SharedFlow.\nO que acontece se o buffer do Channel estiver cheio? A coroutine que chama send() sera suspensa até que haja espaco no buffer. Com trySend(), a operação retorna imediatamente com um resultado indicando se o envio foi bem-sucedido.\nChannels podem causar vazamento de memória? Sim, se você criar um Channel com buffer ilimitado e o produtor for muito mais rápido que o consumidor, os dados acumulam na memória. Use buffers limitados e monitore o fluxo de dados.\n","permalink":"https://kotlin.dev.br/glossario/channel/","summary":"\u003ch2 id=\"o-que-é-channel-em-kotlin\"\u003eO que é Channel em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUm \u003ccode\u003eChannel\u003c/code\u003e em Kotlin é uma estrutura para \u003cstrong\u003ecomunicação entre \u003ca href=\"/glossario/coroutine/\"\u003ecoroutines\u003c/a\u003e\u003c/strong\u003e. Funciona como uma fila: uma coroutine envia dados pelo canal e outra recebe do outro lado. E o jeito mais seguro de trocar informações entre coroutines sem problemas de concorrencia. O conceito foi diretamente inspirado pelos channels de \u003ca href=\"https://golang.com.br/\"\u003eGo\u003c/a\u003e — a implementação em Kotlin segue padrões similares, mas adaptados para o ecossistema de coroutines da JVM.\u003c/p\u003e","title":"Channel em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Flow em Kotlin? O Flow é o mecanismo do Kotlin para trabalhar com streams de dados assíncronos. Enquanto uma função suspend retorna um único valor, um Flow pode emitir múltiplos valores ao longo do tempo, um de cada vez.\nPense no Flow como uma torneira: os dados vão saindo conforme são produzidos, e você consome na hora que quiser.\nSintaxe básica import kotlinx.coroutines.* import kotlinx.coroutines.flow.* fun contagem(): Flow\u0026lt;Int\u0026gt; = flow { for (i in 1..5) { delay(500) emit(i) } } fun main() = runBlocking { contagem().collect { valor -\u0026gt; println(\u0026#34;Recebido: $valor\u0026#34;) } } O flow { } cria o produtor, o emit() envia cada valor e o collect consome. Simples assim.\nFlow é \u0026ldquo;cold\u0026rdquo; Uma característica importante: o Flow é cold, ou seja, ele só começa a produzir dados quando alguém chama collect. Se ninguém coletar, nada acontece.\nval meuFlow = flow { println(\u0026#34;Flow iniciado!\u0026#34;) // Só executa quando alguém coletar emit(1) emit(2) } Operadores úteis Flow vem com vários operadores pra transformar e filtrar dados:\nfun main() = runBlocking { (1..10).asFlow() .filter { it % 2 == 0 } .map { it * it } .collect { println(it) } // 4, 16, 36, 64, 100 } Alguns operadores mais usados:\nmap — transforma cada valor filter — filtra valores take — pega os N primeiros onEach — executa ação em cada valor catch — trata erros no fluxo Exemplo prático: atualizações em tempo real fun atualizacoesDePreco(): Flow\u0026lt;Double\u0026gt; = flow { val precos = listOf(45.50, 46.20, 44.80, 47.10) for (preco in precos) { delay(1000) emit(preco) } } fun main() = runBlocking { atualizacoesDePreco().collect { preco -\u0026gt; println(\u0026#34;Preço atual: R$ $preco\u0026#34;) } } Flow é ideal para dados que chegam aos poucos: eventos de UI, atualizações de banco de dados, respostas de WebSocket e qualquer cenário onde você precisa reagir a mudanças contínuas.\nStateFlow e SharedFlow Além do Flow tradicional (cold), Kotlin oferece variantes hot que mantêm estado ou compartilham emissões entre múltiplos coletores:\nimport kotlinx.coroutines.flow.* // StateFlow: mantém o último valor emitido val _contador = MutableStateFlow(0) val contador: StateFlow\u0026lt;Int\u0026gt; = _contador.asStateFlow() // SharedFlow: broadcast para múltiplos coletores val _eventos = MutableSharedFlow\u0026lt;String\u0026gt;() val eventos: SharedFlow\u0026lt;String\u0026gt; = _eventos.asSharedFlow() O StateFlow é muito usado em arquiteturas como MVVM no Android, substituindo o LiveData com uma API baseada em coroutines. Já o SharedFlow é ideal para eventos que não devem ser repetidos, como navegação ou exibição de mensagens.\nCombinando Flows Você pode combinar múltiplos Flows para criar fluxos de dados mais complexos:\nfun main() = runBlocking { val nomes = flowOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;, \u0026#34;Carla\u0026#34;) val idades = flowOf(25, 30, 28) nomes.zip(idades) { nome, idade -\u0026gt; \u0026#34;$nome tem $idade anos\u0026#34; }.collect { println(it) } // Ana tem 25 anos // Bruno tem 30 anos // Carla tem 28 anos } O operador combine é outra opção: ele re-emite sempre que qualquer um dos Flows emite um novo valor, usando o último valor disponível de cada um.\nCasos de Uso no Mundo Real Atualizações de interface no Android: usar StateFlow no ViewModel para expor o estado da tela e coletar no Fragment ou Composable, garantindo que a UI sempre reflita o estado mais recente. Busca com debounce: capturar o texto digitado pelo usuário como um Flow e aplicar debounce(300) seguido de distinctUntilChanged() e flatMapLatest para realizar buscas sem sobrecarregar a API. Monitoramento de conexão de rede: criar um Flow que emite o status de conectividade do dispositivo usando callbacks do sistema, permitindo que a aplicação reaja automaticamente a mudanças de rede. Leitura contínua de sensores ou dados IoT: usar Flow para modelar streams de dados de sensores como temperatura, localização GPS ou dados de dispositivos Bluetooth, processando cada leitura conforme ela chega. Boas Práticas Prefira expor StateFlow ou SharedFlow como tipos imutáveis na API pública e manter o MutableStateFlow ou MutableSharedFlow como privado. Use o operador catch para tratar erros dentro do pipeline do Flow em vez de envolver o collect em um bloco try-catch. Utilize flowOn(Dispatchers.IO) para mover a produção de dados para uma thread de IO, mantendo a coleta na thread principal quando necessário. Evite coletar Flows diretamente em GlobalScope. No Android, prefira lifecycleScope ou repeatOnLifecycle para evitar vazamentos de memória. Use stateIn e shareIn para converter Flows cold em hot quando múltiplos consumidores precisam do mesmo fluxo de dados. Erros Comuns Coletar o mesmo Flow cold múltiplas vezes sem perceber: cada chamada a collect reinicia a produção do Flow. Se isso não é o comportamento desejado, converta para SharedFlow com shareIn. Esquecer que collect é uma função suspensa: tentar chamar collect fora de uma coroutine causa erro de compilação. Sempre colete dentro de um escopo de coroutine. Bloquear dentro de um flow { }: usar operações bloqueantes como Thread.sleep() dentro do builder flow em vez de delay() trava a coroutine e anula os benefícios da abordagem assíncrona. Não tratar erros no pipeline: se uma exceção ocorre dentro de um Flow e não é capturada com catch, ela se propaga para o coletor e pode derrubar a coroutine inteira. Confundir StateFlow com LiveData: embora ambos mantenham o último valor, StateFlow requer coleta em coroutines e não é lifecycle-aware por padrão. No Android, combine com repeatOnLifecycle. Perguntas Frequentes Qual a diferença entre Flow e Sequence em Kotlin? Sequence é síncrono e processa elementos sob demanda na mesma thread. Flow é assíncrono e trabalha com coroutines, permitindo operações suspensas como chamadas de rede e delays entre emissões.\nQuando devo usar StateFlow em vez de Flow? Use StateFlow quando precisa manter o último valor emitido e compartilhar entre múltiplos coletores, como o estado de uma tela. Use Flow quando os dados são produzidos sob demanda e cada coletor deve receber seu próprio fluxo independente.\nFlow substitui RxJava? Flow cobre a grande maioria dos casos de uso do RxJava para projetos Kotlin, com a vantagem de integração nativa com coroutines. Para projetos novos em Kotlin, Flow é a escolha recomendada.\nPosso usar Flow sem coroutines? Não. Flow faz parte do pacote kotlinx.coroutines.flow e depende de coroutines para funcionar. A coleta de um Flow sempre acontece dentro de uma função suspensa.\nTermos Relacionados Coroutine — mecanismo de concorrência que sustenta o funcionamento do Flow Suspend — modificador que permite funções assíncronas usadas dentro de Flows Lambda — funções anônimas usadas nos operadores de Flow como map e filter Higher-Order Function — padrão de funções que recebem outras funções, base dos operadores de Flow ","permalink":"https://kotlin.dev.br/glossario/flow/","summary":"\u003ch2 id=\"o-que-é-flow-em-kotlin\"\u003eO que é Flow em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO \u003ccode\u003eFlow\u003c/code\u003e é o mecanismo do Kotlin para trabalhar com \u003cstrong\u003estreams de dados assíncronos\u003c/strong\u003e. Enquanto uma função \u003ccode\u003esuspend\u003c/code\u003e retorna um único valor, um Flow pode emitir \u003cstrong\u003emúltiplos valores\u003c/strong\u003e ao longo do tempo, um de cada vez.\u003c/p\u003e\n\u003cp\u003ePense no Flow como uma torneira: os dados vão saindo conforme são produzidos, e você consome na hora que quiser.\u003c/p\u003e\n\u003ch3 id=\"sintaxe-básica\"\u003eSintaxe básica\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003ekotlinx.coroutines.*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003ekotlinx.coroutines.flow.*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003econtagem\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e \u003cspan class=\"n\"\u003eFlow\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eflow\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"k\"\u003ein\u003c/span\u003e \u003cspan class=\"m\"\u003e1.\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003edelay\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e500\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eemit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erunBlocking\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003econtagem\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003ecollect\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"n\"\u003evalor\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Recebido: \u003c/span\u003e\u003cspan class=\"si\"\u003e$valor\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eO \u003ccode\u003eflow { }\u003c/code\u003e cria o produtor, o \u003ccode\u003eemit()\u003c/code\u003e envia cada valor e o \u003ccode\u003ecollect\u003c/code\u003e consome. Simples assim.\u003c/p\u003e","title":"Flow em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Coroutine em Kotlin? Coroutines são o mecanismo do Kotlin para lidar com programação assíncrona de forma simples e eficiente. Em vez de usar callbacks aninhados ou threads pesadas, você escreve código assíncrono que parece sequencial \u0026ndash; fácil de ler, fácil de manter.\nPense nas coroutines como \u0026ldquo;threads leves\u0026rdquo;. Você pode rodar milhares delas sem estourar a memória, porque elas não criam threads do sistema operacional \u0026ndash; são gerenciadas pelo próprio Kotlin. O conceito é similar às goroutines de Go e ao async/await de Rust, cada linguagem com sua abordagem para concorrência leve.\nUma analogia útil: imagine um restaurante. Threads tradicionais seriam como ter um garçom exclusivo para cada mesa \u0026ndash; caro e limitado. Coroutines funcionam como um garçom eficiente que atende várias mesas: enquanto espera o pedido de uma mesa ser preparado na cozinha, ele vai atender outra. O garçom (thread) nunca fica parado, é o restaurante funciona com poucos garçons atendendo muitas mesas.\nPor que usar coroutines? O problema clássico de código assíncrono é o tal do \u0026ldquo;callback hell\u0026rdquo;. Coroutines resolvem isso permitindo que você escreva código que parece síncrono, mas executa de forma assíncrona por baixo dos panos.\nExemplo básico import kotlinx.coroutines.* fun main() = runBlocking { println(\u0026#34;Início\u0026#34;) launch { delay(1000) println(\u0026#34;Coroutine finalizada!\u0026#34;) } println(\u0026#34;Fazendo outras coisas...\u0026#34;) delay(1500) println(\u0026#34;Fim\u0026#34;) } Saída:\nInício Fazendo outras coisas... Coroutine finalizada! Fim O launch cria uma nova coroutine, e o delay suspende a execução sem bloquear a thread. Enquanto uma coroutine está esperando, outras podem rodar tranquilamente.\nConceitos fundamentais CoroutineScope: define o ciclo de vida das coroutines launch: inicia uma coroutine que não retorna valor async: inicia uma coroutine que retorna um resultado suspend: marca uma função que pode ser suspensa Dispatchers: controlam em qual thread a coroutine vai rodar Exemplo com chamada de rede simulada import kotlinx.coroutines.* suspend fun buscarDados(): String { delay(2000) // Simula uma chamada de rede return \u0026#34;Dados carregados com sucesso\u0026#34; } fun main() = runBlocking { println(\u0026#34;Buscando dados...\u0026#34;) val resultado = buscarDados() println(resultado) } Quando usar? Coroutines são essenciais para operações de I/O (chamadas de rede, banco de dados, leitura de arquivos), processamento em background e qualquer tarefa que não deveria travar a interface do usuário. No Android, são praticamente obrigatórias hoje em dia.\nChamadas paralelas com async e await Quando você precisa fazer várias operações ao mesmo tempo e combinar os resultados, async é a escolha certa:\nimport kotlinx.coroutines.* suspend fun buscarUsuario(): String { delay(1000) return \u0026#34;Karina\u0026#34; } suspend fun buscarPedidos(): List\u0026lt;String\u0026gt; { delay(1200) return listOf(\u0026#34;Pedido #1\u0026#34;, \u0026#34;Pedido #2\u0026#34;, \u0026#34;Pedido #3\u0026#34;) } fun main() = runBlocking { val inicio = System.currentTimeMillis() val usuario = async { buscarUsuario() } val pedidos = async { buscarPedidos() } println(\u0026#34;Usuário: ${usuario.await()}\u0026#34;) println(\u0026#34;Pedidos: ${pedidos.await()}\u0026#34;) val tempo = System.currentTimeMillis() - inicio println(\u0026#34;Tempo total: ${tempo}ms\u0026#34;) // ~1200ms, nao ~2200ms } As duas chamadas rodam em paralelo, e o tempo total é o da chamada mais lenta, não a soma das duas.\nTratamento de erros com coroutines Lidar com exceções em coroutines exige atenção ao scope e ao job:\nimport kotlinx.coroutines.* fun main() = runBlocking { val handler = CoroutineExceptionHandler { _, excecao -\u0026gt; println(\u0026#34;Erro capturado: ${excecao.message}\u0026#34;) } val scope = CoroutineScope(Dispatchers.Default + handler) scope.launch { println(\u0026#34;Iniciando operacao...\u0026#34;) delay(500) throw RuntimeException(\u0026#34;Falha na conexão\u0026#34;) } delay(1000) // Aguarda para ver o resultado // Saída: Erro capturado: Falha na conexão } Coroutines com Flow para dados em sequência Para fluxos de dados contínuos, combine coroutines com Flow:\nimport kotlinx.coroutines.* import kotlinx.coroutines.flow.* fun monitorarTemperatura(): Flow\u0026lt;Double\u0026gt; = flow { val sensores = listOf(22.5, 23.1, 24.0, 23.8, 25.2) for (temp in sensores) { delay(500) // Simula leitura do sensor emit(temp) } } fun main() = runBlocking { monitorarTemperatura() .filter { it \u0026gt; 23.0 } .collect { temperatura -\u0026gt; println(\u0026#34;Alerta: temperatura em ${temperatura} graus\u0026#34;) } } Casos de Uso no Mundo Real Chamadas de API em Android: usar viewModelScope.launch para buscar dados de APIs REST sem travar a UI, substituindo AsyncTask e RxJava. Processamento de arquivos: ler e processar arquivos grandes linha por linha usando coroutines com Dispatchers.IO para não bloquear a thread principal. Websockets e streaming: manter conexões ativas com servidores usando Flow e Channel para receber dados em tempo real. Operações em banco de dados: executar consultas Room ou Exposed em coroutines para manter a responsividade da aplicação. Tarefas periódicas: usar while(isActive) com delay para executar verificações periódicas sem criar timers tradicionais. Boas Práticas Nunca use runBlocking em código de produção (exceto em main() ou testes). Ele bloqueia a thread, anulando o propósito das coroutines. Sempre defina um Dispatcher adequado: use Dispatchers.IO para operações de I/O, Dispatchers.Default para CPU intensiva e Dispatchers.Main para atualizações de UI. Respeite a estrutura de concorrência (structured concurrency): lance coroutines dentro de um scope adequado para que sejam canceladas automaticamente quando o scope é destruído. Use withContext para trocar de dispatcher em vez de lançar uma nova coroutine. Prefira Flow sobre Channel para fluxos de dados frios (que só produzem quando alguém consome). Erros Comuns Esquecer de tratar exceções: exceções em launch propagam e cancelam o scope pai. Use try-catch dentro da coroutine ou um CoroutineExceptionHandler. Usar GlobalScope indiscriminadamente: coroutines lançadas em GlobalScope não respeitam ciclo de vida e podem causar vazamento de memória. Use scopes vinculados ao componente (como viewModelScope no Android). Chamar funções suspend sem estar em uma coroutine: funções suspend só podem ser chamadas de dentro de outra função suspend ou de um builder como launch ou async. Não cancelar coroutines desnecessárias: se o usuário saiu de uma tela, as coroutines daquela tela devem ser canceladas. Usar scopes vinculados ao ciclo de vida resolve isso automaticamente. Perguntas Frequentes Qual a diferença entre launch e async? launch inicia uma coroutine que não retorna resultado (retorna um Job). async inicia uma coroutine que retorna um resultado encapsulado em um Deferred, acessível via await().\nCoroutines substituem threads? Não completamente. Coroutines rodam sobre threads, mas permitem multiplexar muitas tarefas em poucas threads. Para tarefas CPU-bound pesadas, você ainda precisa de threads adequadas via Dispatchers.Default.\nPosso usar coroutines em projetos backend? Sim. Frameworks como Ktor são construídos sobre coroutines. Spring Boot também oferece suporte completo a coroutines com suspend functions em controllers.\nO que acontece se uma coroutine dentro de async lançar uma exceção? A exceção é encapsulada no Deferred e será relançada quando você chamar await(). Use try-catch ao redor do await() ou um SupervisorScope para evitar que o erro cancele as coroutines irmãs.\n","permalink":"https://kotlin.dev.br/glossario/coroutine/","summary":"\u003ch2 id=\"o-que-é-coroutine-em-kotlin\"\u003eO que é Coroutine em Kotlin?\u003c/h2\u003e\n\u003cp\u003eCoroutines são o mecanismo do Kotlin para lidar com \u003cstrong\u003eprogramação assíncrona\u003c/strong\u003e de forma simples e eficiente. Em vez de usar callbacks aninhados ou threads pesadas, você escreve código assíncrono que parece sequencial \u0026ndash; fácil de ler, fácil de manter.\u003c/p\u003e\n\u003cp\u003ePense nas coroutines como \u0026ldquo;threads leves\u0026rdquo;. Você pode rodar milhares delas sem estourar a memória, porque elas não criam threads do sistema operacional \u0026ndash; são gerenciadas pelo próprio Kotlin. O conceito é similar às goroutines de \u003ca href=\"https://golang.com.br/\"\u003eGo\u003c/a\u003e e ao async/await de \u003ca href=\"https://rustlang.com.br/\"\u003eRust\u003c/a\u003e, cada linguagem com sua abordagem para concorrência leve.\u003c/p\u003e","title":"Coroutine em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é suspend em Kotlin? A palavra-chave suspend marca uma função que pode ser pausada e retomada sem bloquear a thread em que está rodando. É o coração do sistema de coroutines do Kotlin.\nUma função suspend só pode ser chamada dentro de outra função suspend ou dentro de uma coroutine. O compilador garante isso em tempo de compilação, então não tem como errar.\nSintaxe básica import kotlinx.coroutines.* suspend fun buscarUsuario(id: Int): String { delay(1000) // Simula uma operacao demorada return \u0026#34;Usuário #$id\u0026#34; } fun main() = runBlocking { val usuario = buscarUsuario(42) println(usuario) // Usuário #42 } A função buscarUsuario é suspensa — ela pode pausar no delay e liberar a thread para fazer outras coisas. Quando o tempo passa, ela retoma de onde parou.\nO que acontece por baixo dos panos? Quando o compilador encontra uma função suspend, ele transforma ela numa máquina de estados usando continuations. Na prática, a função é dividida em pedaços que podem ser executados em momentos diferentes.\nVocê não precisa se preocupar com esses detalhes pra usar, mas é bom saber que não tem mágica — é tudo gerado em tempo de compilação.\nCombinando funções suspend import kotlinx.coroutines.* suspend fun buscarNome(): String { delay(500) return \u0026#34;Fernanda\u0026#34; } suspend fun buscarCidade(): String { delay(500) return \u0026#34;Recife\u0026#34; } fun main() = runBlocking { val inicio = System.currentTimeMillis() val nome = buscarNome() val cidade = buscarCidade() val tempo = System.currentTimeMillis() - inicio println(\u0026#34;$nome mora em $cidade (${tempo}ms)\u0026#34;) // Fernanda mora em Recife (~1000ms - sequencial) } No exemplo acima, as chamadas são sequenciais. Se quiser executar em paralelo, use async — aí o tempo cai pela metade.\nExecução paralela com async Quando duas funções suspend são independentes entre si, você pode executá-las em paralelo usando async e await. Isso reduz o tempo total de execução significativamente.\nimport kotlinx.coroutines.* suspend fun buscarPedidos(userId: Int): List\u0026lt;String\u0026gt; { delay(800) return listOf(\u0026#34;Pedido #101\u0026#34;, \u0026#34;Pedido #102\u0026#34;) } suspend fun buscarNotificacoes(userId: Int): List\u0026lt;String\u0026gt; { delay(600) return listOf(\u0026#34;Novo comentário\u0026#34;, \u0026#34;Promoção disponível\u0026#34;) } fun main() = runBlocking { val inicio = System.currentTimeMillis() val pedidos = async { buscarPedidos(1) } val notificacoes = async { buscarNotificacoes(1) } println(\u0026#34;Pedidos: ${pedidos.await()}\u0026#34;) println(\u0026#34;Notificações: ${notificacoes.await()}\u0026#34;) val tempo = System.currentTimeMillis() - inicio println(\u0026#34;Tempo total: ${tempo}ms\u0026#34;) // ~800ms em vez de ~1400ms } Nesse exemplo, ambas as chamadas iniciam ao mesmo tempo. O tempo total é determinado pela operação mais lenta, não pela soma das duas.\nFunções suspend com tratamento de erros Funções suspend funcionam perfeitamente com try-catch, o que torna o tratamento de erros muito mais natural do que callbacks aninhados.\nimport kotlinx.coroutines.* import java.io.IOException suspend fun buscarDadosDoServidor(): String { delay(500) // Simulando uma falha de rede throw IOException(\u0026#34;Falha na conexão\u0026#34;) } fun main() = runBlocking { try { val dados = buscarDadosDoServidor() println(dados) } catch (e: IOException) { println(\u0026#34;Erro ao buscar dados: ${e.message}\u0026#34;) // Erro ao buscar dados: Falha na conexão } } Regras importantes Funções suspend só podem ser chamadas de coroutines ou de outras funções suspend. suspend não torna a função assíncrona por si só — ela apenas permite a suspensão. Funções normais não podem chamar funções suspend diretamente. Casos de Uso no Mundo Real Chamadas de API REST: Funções suspend são ideais para requisições HTTP. Bibliotecas como Ktor Client e Retrofit com suporte a coroutines expõem suas operações como funções suspend, permitindo fazer chamadas de rede sem bloquear a thread principal. Acesso a banco de dados: O Room (Android) e o Exposed (backend) permitem definir queries como funções suspend. Isso garante que consultas pesadas não travem a interface do usuário nem bloqueiem threads do servidor. Leitura e escrita de arquivos: Operações de I/O demoradas podem ser encapsuladas em funções suspend usando withContext(Dispatchers.IO), mantendo a thread principal livre para outras tarefas. Processamento em lote: Quando você precisa processar milhares de itens (enviar emails, gerar relatórios), funções suspend combinadas com Flow permitem processar item a item sem consumir memória excessiva. Boas Práticas Use withContext para trocar de dispatcher: Quando uma função suspend precisa fazer I/O ou computação pesada, envolva o trecho com withContext(Dispatchers.IO) ou withContext(Dispatchers.Default) para não bloquear o dispatcher atual. Mantenha funções suspend seguras para a main thread: Uma função suspend bem escrita pode ser chamada de qualquer dispatcher sem risco. Ela mesma deve cuidar de trocar para o dispatcher adequado internamente. Prefira structured concurrency: Use coroutineScope dentro de funções suspend quando precisar lançar coroutines filhas. Isso garante que todas terminem antes da função retornar. Não marque como suspend sem necessidade: Só adicione suspend quando a função realmente precisa chamar outra função suspensa. Marcar funções desnecessariamente como suspend força quem chama a usar coroutines sem motivo. Documente o dispatcher esperado: Se a função precisa ser chamada de um dispatcher específico, deixe isso claro na documentação com @Throws ou comentários. Erros Comuns Chamar função suspend fora de uma coroutine: O erro mais frequente de quem começa. Funções suspend precisam ser chamadas dentro de runBlocking, launch, async ou outra função suspend. O compilador vai reclamar se você tentar chamar de uma função normal. Usar runBlocking em produção: runBlocking bloqueia a thread atual, anulando a vantagem das coroutines. Use apenas em main() ou em testes. Em código de produção, prefira launch ou async. Esquecer de trocar o dispatcher para I/O: Chamar operações de I/O bloqueantes (como leitura de arquivo com java.io.File) dentro de uma função suspend sem usar withContext(Dispatchers.IO) pode travar o dispatcher principal. Ignorar o cancelamento: Funções suspend devem respeitar o cancelamento da coroutine. Se você faz loops longos, verifique isActive ou use ensureActive() para que o cancelamento funcione corretamente. Misturar callbacks com suspend: Evite usar callbacks dentro de funções suspend. Se precisa integrar com APIs baseadas em callback, use suspendCancellableCoroutine para convertê-las corretamente. Perguntas Frequentes Qual a diferença entre suspend e async? suspend é um modificador de função que indica que ela pode ser pausada. async é um builder de coroutine que executa uma função suspend e retorna um Deferred com o resultado. São conceitos complementares: suspend define a capacidade de pausar, e async é uma das formas de executar funções suspensas.\nPosso chamar uma função suspend de Java? Não diretamente. O compilador Kotlin transforma funções suspend adicionando um parâmetro Continuation extra. Para chamá-las de Java, você precisa trabalhar com a API de Continuation manualmente ou usar wrappers que convertem para CompletableFuture.\nFunções suspend rodam em outra thread automaticamente? Não. Uma função suspend roda no dispatcher da coroutine que a chamou. Se precisa rodar em outra thread, use withContext para especificar o dispatcher desejado. A suspensão em si não implica troca de thread.\nQuantas funções suspend posso ter rodando ao mesmo tempo? Não há limite prático imposto pela linguagem. Coroutines são muito leves (ocupam poucos bytes de memória), então é possível ter milhares ou até milhões de coroutines simultâneas, ao contrário de threads que consomem muito mais recursos.\nTermos Relacionados Coroutines — O mecanismo de concorrência do Kotlin que utiliza funções suspend. Flow — Streams assíncronos construídos sobre funções suspend. val — Declaração de variáveis somente leitura, frequentemente usada para armazenar resultados de funções suspend. fun — A palavra-chave para declarar funções em Kotlin, combinada com suspend para criar funções suspensas. suspend é a base de tudo que envolve concorrência em Kotlin. Dominar esse conceito abre as portas para coroutines, Flow e muito mais.\n","permalink":"https://kotlin.dev.br/glossario/suspend/","summary":"\u003ch2 id=\"o-que-é-suspend-em-kotlin\"\u003eO que é \u003ccode\u003esuspend\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eA palavra-chave \u003ccode\u003esuspend\u003c/code\u003e marca uma função que pode ser \u003cstrong\u003epausada e retomada\u003c/strong\u003e sem bloquear a thread em que está rodando. É o coração do sistema de coroutines do Kotlin.\u003c/p\u003e\n\u003cp\u003eUma função \u003ccode\u003esuspend\u003c/code\u003e só pode ser chamada dentro de outra função \u003ccode\u003esuspend\u003c/code\u003e ou dentro de uma coroutine. O compilador garante isso em tempo de compilação, então não tem como errar.\u003c/p\u003e\n\u003ch3 id=\"sintaxe-básica\"\u003eSintaxe básica\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003ekotlinx.coroutines.*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003esuspend\u003c/span\u003e \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003ebuscarUsuario\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eid\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003edelay\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1000\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Simula uma operacao demorada\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Usuário #\u003c/span\u003e\u003cspan class=\"si\"\u003e$id\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erunBlocking\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003eusuario\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ebuscarUsuario\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e42\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eusuario\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Usuário #42\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eA função \u003ccode\u003ebuscarUsuario\u003c/code\u003e é suspensa — ela pode pausar no \u003ccode\u003edelay\u003c/code\u003e e liberar a thread para fazer outras coisas. Quando o tempo passa, ela retoma de onde parou.\u003c/p\u003e","title":"Suspend em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Companion Object em Kotlin? O companion object é um objeto especial declarado dentro de uma classe que funciona como o equivalente aos membros estáticos do Java. Com ele, você pode acessar propriedades e funções diretamente pelo nome da classe, sem precisar criar uma instância.\nKotlin não tem a palavra-chave static. Em vez disso, usa companion objects \u0026ndash; uma abordagem mais flexível e orientada a objetos.\nPense no companion object como a \u0026ldquo;recepção\u0026rdquo; de um prédio comercial. Você não precisa entrar em nenhuma sala específica (instância) para obter informações gerais \u0026ndash; basta perguntar na recepção. Da mesma forma, o companion object guarda informações e funcionalidades que pertencem à classe como um todo, não a uma instância individual.\nSintaxe básica class Configuração { companion object { const val VERSAO = \u0026#34;2.1.0\u0026#34; val AMBIENTE = \u0026#34;producao\u0026#34; fun info(): String { return \u0026#34;Versão $VERSAO - Ambiente: $AMBIENTE\u0026#34; } } } fun main() { println(Configuração.VERSAO) // 2.1.0 println(Configuração.info()) // Versão 2.1.0 - Ambiente: producao } Repare que você acessa versão e info() direto pela classe, sem instanciar nada.\nFactory methods Um dos usos mais comuns do companion object é para criar factory methods \u0026ndash; funções que constroem objetos de formas alternativas:\ndata class Usuario(val nome: String, val email: String) { companion object { fun criarAdmin(nome: String): Usuario { return Usuario(nome, \u0026#34;$nome@admin.com.br\u0026#34;) } fun criarConvidado(): Usuario { return Usuario(\u0026#34;Convidado\u0026#34;, \u0026#34;convidado@temp.com.br\u0026#34;) } } } fun main() { val admin = Usuario.criarAdmin(\u0026#34;karina\u0026#34;) val guest = Usuario.criarConvidado() println(admin) // Usuario(nome=karina, email=karina@admin.com.br) println(guest) // Usuario(nome=Convidado, email=convidado@temp.com.br) } Companion object com nome e interface O companion object pode ter um nome e até implementar interfaces:\ninterface Serializavel { fun fromJson(json: String): Any } class Produto(val nome: String) { companion object Fabrica : Serializavel { override fun fromJson(json: String): Produto { return Produto(json) // simplificado } } } Quando usar? Use companion object para constantes, factory methods, e qualquer funcionalidade que pertença à classe como um todo e não a uma instância específica. É o jeito Kotlin de lidar com o que seria static em Java.\nCompanion object com extension functions Você pode adicionar extension functions ao companion object de uma classe, o que permite estender funcionalidades sem modificar o código original:\nclass Validador { companion object } fun Validador.Companion.cpf(valor: String): Boolean { return valor.replace(\u0026#34;[^0-9]\u0026#34;.toRegex(), \u0026#34;\u0026#34;).length == 11 } fun Validador.Companion.email(valor: String): Boolean { return valor.contains(\u0026#34;@\u0026#34;) \u0026amp;\u0026amp; valor.contains(\u0026#34;.\u0026#34;) } fun main() { println(Validador.cpf(\u0026#34;123.456.789-00\u0026#34;)) // true println(Validador.email(\u0026#34;teste@email.com\u0026#34;)) // true println(Validador.email(\u0026#34;invalido\u0026#34;)) // false } Companion object como singleton de configuração Um padrão muito utilizado é usar companion object para gerenciar configurações ou registros de uma classe:\nclass Logger private constructor(val nome: String) { companion object { private val instancias = mutableMapOf\u0026lt;String, Logger\u0026gt;() fun obter(nome: String): Logger { return instancias.getOrPut(nome) { println(\u0026#34;Criando logger para: $nome\u0026#34;) Logger(nome) } } } fun info(mensagem: String) { println(\u0026#34;[$nome] INFO: $mensagem\u0026#34;) } } fun main() { val logA = Logger.obter(\u0026#34;App\u0026#34;) val logB = Logger.obter(\u0026#34;App\u0026#34;) // reutiliza a instância existente val logC = Logger.obter(\u0026#34;Database\u0026#34;) logA.info(\u0026#34;Aplicação iniciada\u0026#34;) logC.info(\u0026#34;Conexão estabelecida\u0026#34;) println(logA === logB) // true -- mesma instância } Casos de Uso no Mundo Real Constantes de configuração: agrupar URLs de API, chaves de preferências, códigos de erro e outras constantes que pertencem ao contexto da classe. Factory methods com válidação: criar instâncias com regras de negócio, como Usuario.fromCsv(linha) ou Pedido.criarRascunho(). Interoperabilidade com Java: usar a anotação @JvmStatic em métodos do companion object para que o código Java possa chamar como métodos estáticos reais. Serialização e desserialização: implementar funções fromJson() e fromMap() no companion object para converter dados externos em objetos Kotlin. Registros e caches: manter um mapa de instâncias para evitar criação duplicada, como no padrão mostrado acima. Boas Práticas Use const val para constantes primitivas: dentro do companion object, declare constantes de tipos primitivos e String com const val para garantir que sejam inlined pelo compilador. Não coloque lógica de negócio pesada no companion object. Ele deve conter funcionalidades utilitárias relacionadas à classe, não regras complexas. Dê um nome ao companion object quando ele implementa uma interface ou quando você quer deixar o propósito claro: companion object Factory. Use @JvmStatic em projetos mistos Kotlin/Java para facilitar a interoperabilidade. Prefira object de nível superior quando a funcionalidade não está diretamente ligada a uma classe específica. Erros Comuns Confundir companion object com instância da classe: o companion object é compartilhado entre todas as instâncias. Alterar uma propriedade var dentro dele afeta todas as partes do código que a acessam. Usar companion object para estado mutável global: isso cria acoplamento e dificulta testes. Se precisa de estado compartilhado, considere injeção de dependência. Esquecer que cada classe só pode ter um companion object: se você precisa de múltiplos agrupamentos, use objects regulares nomeados dentro da classe. Não usar const em constantes String: declarar val em vez de const val para strings constantes impede a otimização do compilador e gera um campo com getter desnecessário. Perguntas Frequentes Qual a diferença entre companion object e object declaration? O companion object vive dentro de uma classe e permite acessar seus membros pelo nome da classe (como MinhaClasse.função()). Um object declaration é um singleton independente, acessado pelo próprio nome.\nPosso ter mais de um companion object por classe? Não. Cada classe pode ter no máximo um companion object. Se precisar de mais agrupamentos, use object nomeados regulares dentro da classe.\nO companion object é inicializado quando? Ele é inicializado na primeira vez que a classe é referenciada, de forma similar ao carregamento de classes no Java. Isso segue o padrão de inicialização lazy.\nComo acessar o companion object de Kotlin a partir do Java? Use MinhaClasse.Companion.método(). Se quiser acessar como método estático, adicione @JvmStatic ao método dentro do companion object.\n","permalink":"https://kotlin.dev.br/glossario/companion-object/","summary":"\u003ch2 id=\"o-que-é-companion-object-em-kotlin\"\u003eO que é Companion Object em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO \u003ccode\u003ecompanion object\u003c/code\u003e é um objeto especial declarado \u003cstrong\u003edentro de uma classe\u003c/strong\u003e que funciona como o equivalente aos membros estáticos do Java. Com ele, você pode acessar propriedades e funções diretamente pelo nome da classe, sem precisar criar uma instância.\u003c/p\u003e\n\u003cp\u003eKotlin não tem a palavra-chave \u003ccode\u003estatic\u003c/code\u003e. Em vez disso, usa companion objects \u0026ndash; uma abordagem mais flexível e orientada a objetos.\u003c/p\u003e\n\u003cp\u003ePense no companion object como a \u0026ldquo;recepção\u0026rdquo; de um prédio comercial. Você não precisa entrar em nenhuma sala específica (instância) para obter informações gerais \u0026ndash; basta perguntar na recepção. Da mesma forma, o companion object guarda informações e funcionalidades que pertencem à classe como um todo, não a uma instância individual.\u003c/p\u003e","title":"Companion Object em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é object em Kotlin? A palavra-chave object em Kotlin serve para criar singletons — objetos que existem em uma única instância durante toda a execução do programa. Além disso, object também é usado para criar objetos anônimos, parecidos com as classes anônimas do Java.\nEm Kotlin, o padrão Singleton vem de fábrica. Não precisa de construtor privado, campo estático nem nada disso.\nObject Declaration (Singleton) object GerenciadorDeLog { private val logs = mutableListOf\u0026lt;String\u0026gt;() fun registrar(mensagem: String) { logs.add(mensagem) println(\u0026#34;LOG: $mensagem\u0026#34;) } fun exibirTodos() { logs.forEach { println(it) } } } fun main() { GerenciadorDeLog.registrar(\u0026#34;Aplicação iniciada\u0026#34;) GerenciadorDeLog.registrar(\u0026#34;Usuário fez login\u0026#34;) GerenciadorDeLog.exibirTodos() } Você acessa diretamente pelo nome, sem precisar instanciar. O Kotlin garante que só vai existir uma instância de GerenciadorDeLog no programa inteiro.\nObject Expression (Objeto anônimo) Quando você precisa de um objeto que implementa uma interface ou estende uma classe, mas não quer criar uma classe nomeada, usa object expression:\ninterface Clicavel { fun aoClicar() } fun configurarBotao(acao: Clicavel) { acao.aoClicar() } fun main() { configurarBotao(object : Clicavel { override fun aoClicar() { println(\u0026#34;Botão clicado!\u0026#34;) } }) } Isso é muito útil em callbacks e listeners, principalmente no desenvolvimento Android.\nCompanion Object O companion object é uma forma de criar membros estáticos dentro de uma classe. Ele pertence à classe em si, não a uma instância:\nclass Conexao private constructor(val url: String) { companion object { private const val URL_PADRAO = \u0026#34;https://api.kotlin.dev.br\u0026#34; fun criar(): Conexao = Conexao(URL_PADRAO) fun criarCom(url: String): Conexao = Conexao(url) } } fun main() { val conexao1 = Conexao.criar() val conexao2 = Conexao.criarCom(\u0026#34;https://staging.kotlin.dev.br\u0026#34;) println(conexao1.url) // https://api.kotlin.dev.br println(conexao2.url) // https://staging.kotlin.dev.br } O companion object é o equivalente Kotlin dos métodos estáticos e factory methods do Java. Você pode inclusive dar um nome ao companion object e fazê-lo implementar interfaces.\nObject implementando interfaces Um object pode implementar interfaces, o que é muito útil para criar implementações únicas de estratégias ou comportamentos:\ninterface Formatador { fun formatar(valor: Double): String } object FormatadorMoeda : Formatador { override fun formatar(valor: Double): String { return \u0026#34;R$ %.2f\u0026#34;.format(valor) } } object FormatadorPercentual : Formatador { override fun formatar(valor: Double): String { return \u0026#34;%.1f%%\u0026#34;.format(valor * 100) } } fun exibir(valor: Double, formatador: Formatador) { println(formatador.formatar(valor)) } fun main() { exibir(49.90, FormatadorMoeda) // R$ 49.90 exibir(0.157, FormatadorPercentual) // 15.7% } Diferença entre object e class A principal diferença é que object não tem construtor. Ele é inicializado na primeira vez que é acessado (lazy initialization) e permanece vivo enquanto a aplicação rodar.\nCaracterística class object Instâncias Várias Uma só Construtor Sim Não Herança Pode herdar e ser herdada Pode herdar, não pode ser herdada Casos de Uso no Mundo Real Gerenciadores de configuração: armazenar configurações globais da aplicação em um singleton, como URLs de API, chaves de acesso e parâmetros de ambiente. Factory methods com companion object: criar instâncias de classes com construtores privados usando métodos de fábrica no companion object, seguindo o padrão Factory. Implementação de listeners no Android: usar object expressions para criar listeners de clique, scroll e outros eventos sem precisar criar classes separadas. Repositórios e serviços em aplicações simples: em projetos menores sem injeção de dependência, usar object declarations para repositórios e serviços que precisam ser únicos. Boas Práticas Use object para singletons genuínos que realmente precisam ter uma única instância global. Não abuse do padrão — em projetos maiores, prefira injeção de dependência. Prefira companion object para factory methods e constantes associadas a uma classe, em vez de funções de nível de pacote. Dê nomes significativos aos seus companion objects quando eles implementarem interfaces, pois isso melhora a legibilidade ao referenciar externamente. Evite armazenar estado mutável em object declarations em ambientes multi-thread sem sincronização adequada, pois singletons são compartilhados entre threads. Use object expressions em vez de lambdas quando precisar implementar interfaces com múltiplos métodos. Erros Comuns Confundir object declaration com object expression: object declaration cria um singleton nomeado; object expression cria um objeto anônimo descartável. São usos diferentes da mesma palavra-chave. Armazenar estado mutável sem thread safety: como o object é compartilhado globalmente, modificar propriedades mutáveis sem sincronização pode causar race conditions. Usar object em vez de injeção de dependência: em projetos com testes automatizados, singletons via object dificultam a criação de mocks. Prefira DI frameworks como Koin ou Hilt. Esquecer que companion object é uma instância real: diferente dos membros estáticos do Java, o companion object é um objeto real que pode implementar interfaces e ser passado como argumento. Criar dependências circulares entre objects: como objects são inicializados sob demanda (lazy), dependências circulares podem causar comportamentos inesperados ou deadlocks. Perguntas Frequentes Quando o object é inicializado? O object declaration é inicializado de forma lazy, ou seja, na primeira vez que é acessado. A JVM garante que essa inicialização é thread-safe.\nPosso usar object com data class? Não. Data classes precisam ter pelo menos um parâmetro no construtor, e objects não têm construtor. Se você precisa de um singleton com dados, use um object declaration com propriedades normais.\nQual a diferença entre object e companion object? O object cria um singleton independente. O companion object existe dentro de uma classe e funciona como os membros estáticos do Java. Cada classe pode ter apenas um companion object.\nO object do Kotlin é thread-safe? A inicialização do object é thread-safe graças à JVM. Porém, as operações sobre propriedades mutáveis do object não são automaticamente thread-safe e precisam de sincronização manual.\nTermos Relacionados Sealed Class — hierarquias fechadas que frequentemente usam object para subtipos sem dados Companion Object — membros estáticos dentro de classes Class — a estrutura básica para criar tipos em Kotlin Interface — contratos que objects podem implementar Use object quando precisar de uma instância única e global, como gerenciadores, configurações ou utilitários.\n","permalink":"https://kotlin.dev.br/glossario/object/","summary":"\u003ch2 id=\"o-que-é-object-em-kotlin\"\u003eO que é \u003ccode\u003eobject\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eA palavra-chave \u003ccode\u003eobject\u003c/code\u003e em Kotlin serve para criar \u003cstrong\u003esingletons\u003c/strong\u003e — objetos que existem em uma única instância durante toda a execução do programa. Além disso, \u003ccode\u003eobject\u003c/code\u003e também é usado para criar \u003cstrong\u003eobjetos anônimos\u003c/strong\u003e, parecidos com as classes anônimas do Java.\u003c/p\u003e\n\u003cp\u003eEm Kotlin, o padrão Singleton vem de fábrica. Não precisa de construtor privado, campo estático nem nada disso.\u003c/p\u003e\n\u003ch3 id=\"object-declaration-singleton\"\u003eObject Declaration (Singleton)\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eobject\u003c/span\u003e \u003cspan class=\"nc\"\u003eGerenciadorDeLog\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eprivate\u003c/span\u003e \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003elogs\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emutableListOf\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003eregistrar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emensagem\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003elogs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emensagem\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;LOG: \u003c/span\u003e\u003cspan class=\"si\"\u003e$mensagem\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003eexibirTodos\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003elogs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eforEach\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eit\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nc\"\u003eGerenciadorDeLog\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eregistrar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Aplicação iniciada\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nc\"\u003eGerenciadorDeLog\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eregistrar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Usuário fez login\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nc\"\u003eGerenciadorDeLog\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexibirTodos\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eVocê acessa diretamente pelo nome, sem precisar instanciar. O Kotlin garante que só vai existir uma instância de \u003ccode\u003eGerenciadorDeLog\u003c/code\u003e no programa inteiro.\u003c/p\u003e","title":"Object em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Data Class em Kotlin? Uma data class em Kotlin é uma classe feita especialmente para armazenar dados. Quando você declara uma classe com o modificador data, o compilador gera automaticamente os métodos equals(), hashCode(), toString(), copy() e funções componentN() \u0026ndash; tudo de graça.\nEm Java, você precisaria escrever tudo isso na mão (ou usar uma biblioteca). Em Kotlin, basta uma linha.\nPense na data class como um formulário padronizado. Quando você preenche um formulário no cartório, os campos já estão definidos (nome, CPF, endereço) e dois formulários com os mesmos dados preenchidos são considerados equivalentes, independente de serem folhas de papel diferentes. A data class funciona da mesma forma: dois objetos com os mesmos valores são considerados iguais.\nSintaxe básica data class Usuario(val nome: String, val email: String, val idade: Int) fun main() { val user = Usuario(\u0026#34;Mariana\u0026#34;, \u0026#34;mari@email.com\u0026#34;, 30) println(user) // Usuario(nome=Mariana, email=mari@email.com, idade=30) } Olha só: o toString() já vem formatado bonitinho, sem você fazer nada.\nComparação automática Com data class, a comparação entre objetos é feita pelo conteúdo, não pela referência:\nval a = Usuario(\u0026#34;Lucas\u0026#34;, \u0026#34;lucas@email.com\u0026#34;, 25) val b = Usuario(\u0026#34;Lucas\u0026#34;, \u0026#34;lucas@email.com\u0026#34;, 25) println(a == b) // true — mesmo conteúdo println(a === b) // false — objetos diferentes na memoria A função copy() Uma das funcionalidades mais práticas é o copy(), que cria uma cópia do objeto permitindo alterar apenas alguns campos:\nval original = Usuario(\u0026#34;Ana\u0026#34;, \u0026#34;ana@email.com\u0026#34;, 22) val atualizado = original.copy(idade = 23) println(atualizado) // Usuario(nome=Ana, email=ana@email.com, idade=23) Isso é especialmente útil quando você trabalha com objetos imutáveis e precisa criar variações.\nDestructuring As funções componentN() geradas permitem usar destructuring:\nval (nome, email, idade) = Usuario(\u0026#34;Pedro\u0026#34;, \u0026#34;pedro@email.com\u0026#34;, 35) println(\u0026#34;$nome ($email) - $idade anos\u0026#34;) Regras importantes O construtor primário precisa ter pelo menos um parâmetro. Todos os parâmetros do construtor devem ser val ou var. Data classes não podem ser abstract, open, sealed ou inner. Data classes são perfeitas pra representar entidades, respostas de API, configurações e qualquer estrutura que carregue dados no seu projeto Kotlin.\nData class com propriedades fora do construtor Propriedades declaradas no corpo da classe não participam de equals(), hashCode(), toString() e copy(). Isso é útil para campos computados ou auxiliares:\ndata class Produto(val nome: String, val preco: Double) { var desconto: Double = 0.0 val precoFinal: Double get() = preco * (1 - desconto) } fun main() { val p1 = Produto(\u0026#34;Notebook\u0026#34;, 4500.0) val p2 = Produto(\u0026#34;Notebook\u0026#34;, 4500.0) p1.desconto = 0.10 println(p1 == p2) // true -- desconto nao participa do equals println(p1.precoFinal) // 4050.0 println(p2.precoFinal) // 4500.0 } Data class como modelo de API Um cenário muito comum é usar data classes para representar respostas de APIs, combinando com serialização:\ndata class RespostaApi\u0026lt;T\u0026gt;( val sucesso: Boolean, val dados: T?, val mensagem: String, val timestamp: Long = System.currentTimeMillis() ) data class Endereco( val rua: String, val cidade: String, val estado: String, val cep: String ) fun main() { val endereco = Endereco(\u0026#34;Rua das Flores\u0026#34;, \u0026#34;São Paulo\u0026#34;, \u0026#34;SP\u0026#34;, \u0026#34;01001-000\u0026#34;) val resposta = RespostaApi( sucesso = true, dados = endereco, mensagem = \u0026#34;Endereço encontrado\u0026#34; ) println(resposta) // Acesso seguro aos dados resposta.dados?.let { println(\u0026#34;Cidade: ${it.cidade}\u0026#34;) } } Data class em coleções Data classes funcionam perfeitamente com collections graças ao hashCode() e equals() gerados automaticamente:\ndata class Contato(val nome: String, val telefone: String) fun main() { val agenda = mutableSetOf\u0026lt;Contato\u0026gt;() agenda.add(Contato(\u0026#34;Ana\u0026#34;, \u0026#34;11999990000\u0026#34;)) agenda.add(Contato(\u0026#34;Bruno\u0026#34;, \u0026#34;11988880000\u0026#34;)) agenda.add(Contato(\u0026#34;Ana\u0026#34;, \u0026#34;11999990000\u0026#34;)) // duplicata ignorada pelo Set println(agenda.size) // 2 val porLetra = agenda.groupBy { it.nome.first() } println(porLetra) // {A=[Contato(nome=Ana, telefone=11999990000)], // B=[Contato(nome=Bruno, telefone=11988880000)]} } Casos de Uso no Mundo Real DTOs (Data Transfer Objects): representar dados que trafegam entre camadas da aplicação, como entre repositório e viewmodel. Respostas de API: modelar JSONs de APIs REST com campos tipados e valores padrão para campos opcionais. Eventos de domínio: representar eventos em arquiteturas orientadas a eventos, como PedidoCriado(id, data, valor). Chaves compostas em mapas: data classes funcionam como chaves de Map graças ao hashCode() consistente. Estado de UI: em aplicações Android com Jetpack Compose, data classes representam o estado da tela (como UiState(loading, data, error)). Boas Práticas Prefira val sobre var nos parâmetros do construtor. Data classes imutáveis são mais seguras em ambientes concorrentes e mais previsíveis. Use copy() para criar variações em vez de tornar propriedades mutáveis. Isso segue o princípio de imutabilidade. Coloque valores padrão nos parâmetros para facilitar a criação de instâncias parciais e testes. Não coloque lógica de negócio complexa dentro de data classes. Elas devem ser contêineres de dados simples. Use sealed classes quando precisar de hierarquia: data classes não podem ser herdadas, mas podem ser subtipos de uma sealed class. Erros Comuns Declarar propriedades mutáveis que afetam igualdade: se você usa var no construtor, alterar um campo depois de adicionar o objeto a um Set ou como chave de um Map pode causar comportamento imprevisível, já que o hashCode muda. Confundir propriedades do corpo com as do construtor: propriedades declaradas fora do construtor primário não participam de equals, hashCode, toString nem copy. Isso é intencional, mas pode surpreender. Criar data classes com muitos parâmetros: se sua data class tem mais de 7-8 parâmetros, considere agrupar campos relacionados em data classes menores. Esquecer que copy() faz cópia rasa: o copy() não clona objetos aninhados. Se um campo é uma MutableList, a cópia e o original compartilham a mesma lista. Perguntas Frequentes Qual a diferença entre data class e class normal? A data class gera automaticamente equals(), hashCode(), toString(), copy() e funções componentN(). Uma classe normal não gera nada disso \u0026ndash; você precisaria implementar manualmente.\nPosso herdar de uma data class? Não diretamente. Data classes são implicitamente final. Se você precisa de hierarquia, use uma sealed class como classe pai e data classes como subtipos.\nData class ou value class, quando usar cada uma? Use data class para estruturas com múltiplos campos. Use value class para envolver um único valor com significado semântico (como Email, Cpf), já que value classes têm otimização de memória.\nO copy() faz cópia profunda? Não. O copy() faz cópia rasa (shallow copy). Propriedades que são objetos mutáveis (como listas mutáveis) serão compartilhadas entre o original e a cópia. Para cópia profunda, você precisa implementar manualmente.\n","permalink":"https://kotlin.dev.br/glossario/data-class/","summary":"\u003ch2 id=\"o-que-é-data-class-em-kotlin\"\u003eO que é Data Class em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUma \u003ccode\u003edata class\u003c/code\u003e em Kotlin é uma classe feita especialmente para \u003cstrong\u003earmazenar dados\u003c/strong\u003e. Quando você declara uma classe com o modificador \u003ccode\u003edata\u003c/code\u003e, o compilador gera automaticamente os métodos \u003ccode\u003eequals()\u003c/code\u003e, \u003ccode\u003ehashCode()\u003c/code\u003e, \u003ccode\u003etoString()\u003c/code\u003e, \u003ccode\u003ecopy()\u003c/code\u003e e funções \u003ccode\u003ecomponentN()\u003c/code\u003e \u0026ndash; tudo de graça.\u003c/p\u003e\n\u003cp\u003eEm Java, você precisaria escrever tudo isso na mão (ou usar uma biblioteca). Em Kotlin, basta uma linha.\u003c/p\u003e\n\u003cp\u003ePense na data class como um formulário padronizado. Quando você preenche um formulário no cartório, os campos já estão definidos (nome, CPF, endereço) e dois formulários com os mesmos dados preenchidos são considerados equivalentes, independente de serem folhas de papel diferentes. A data class funciona da mesma forma: dois objetos com os mesmos valores são considerados iguais.\u003c/p\u003e","title":"Data Class em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"Sobre a vagaA Platform Science busca uma pessoa Engenheira de Desenvolvimento de Software em Testes, nível pleno, para atuação remota a partir de Londrina, Paraná.\nFoco técnicoA posição envolve qualidade de software e automação de testes em um ambiente com linguagens e ferramentas como Kotlin, Java, Python, Go, JavaScript, TypeScript, Selenium, Cypress, Playwright, JUnit, TestNG, PyTest, Postman, RestAssured, Jenkins, GitHub Actions e CircleCI.\nRequisitosExperiência em desenvolvimento ou automação de testes de software.Conhecimento em ferramentas de testes web, APIs e frameworks de automação.Familiaridade com pipelines de CI/CD e práticas de qualidade em engenharia de software.Disponibilidade para trabalho remoto no Brasil.Informações da vagaEmpresa: Platform ScienceSenioridade: PlenoModelo: RemotoLocalidade: Londrina, Paraná, Brasil ","permalink":"https://kotlin.dev.br/vagas/d18kwowtj6shysyp-platform-science-engenheiro-de-desenvolvimento-de-software-em-t/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Platform Science busca uma pessoa Engenheira de Desenvolvimento de Software em Testes, nível pleno, para atuação remota a partir de Londrina, Paraná.\u003c/p\u003e\u003ch3\u003eFoco técnico\u003c/h3\u003e\u003cp\u003eA posição envolve qualidade de software e automação de testes em um ambiente com linguagens e ferramentas como Kotlin, Java, Python, Go, JavaScript, TypeScript, Selenium, Cypress, Playwright, JUnit, TestNG, PyTest, Postman, RestAssured, Jenkins, GitHub Actions e CircleCI.\u003c/p\u003e\u003ch3\u003eRequisitos\u003c/h3\u003e\u003cul\u003e\u003cli\u003eExperiência em desenvolvimento ou automação de testes de software.\u003c/li\u003e\u003cli\u003eConhecimento em ferramentas de testes web, APIs e frameworks de automação.\u003c/li\u003e\u003cli\u003eFamiliaridade com pipelines de CI/CD e práticas de qualidade em engenharia de software.\u003c/li\u003e\u003cli\u003eDisponibilidade para trabalho remoto no Brasil.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eInformações da vaga\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eEmpresa:\u003c/strong\u003e Platform Science\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eSenioridade:\u003c/strong\u003e Pleno\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eModelo:\u003c/strong\u003e Remoto\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eLocalidade:\u003c/strong\u003e Londrina, Paraná, Brasil\u003c/li\u003e\u003c/ul\u003e","title":"Engenheiro de Desenvolvimento de Software em Testes Pleno"},{"content":"Sobre a vagaA Amazon busca uma pessoa Engenheira de Software de nível pleno para atuar presencialmente em São Paulo nos times IES LATECH \u0026amp; GIS.\nTecnologias mencionadasKotlin, Java, C++, C#, Python, Go, JavaScript, C e Clojure.UNIX/Linux, Web Services e AWS.Local de trabalhoVaga presencial em São Paulo, São Paulo, Brasil.\nObservaçãoA descrição detalhada de responsabilidades, requisitos e benefícios não foi fornecida no anúncio original.\n","permalink":"https://kotlin.dev.br/vagas/kx5gnbmmdyldidqc-amazon-engenheiro-a-de-software-ies-latech-gis/","summary":"\u003ch3\u003eSobre a vaga\u003c/h3\u003e\u003cp\u003eA Amazon busca uma pessoa Engenheira de Software de nível pleno para atuar presencialmente em São Paulo nos times IES LATECH \u0026amp; GIS.\u003c/p\u003e\u003ch3\u003eTecnologias mencionadas\u003c/h3\u003e\u003cul\u003e\u003cli\u003eKotlin, Java, C++, C#, Python, Go, JavaScript, C e Clojure.\u003c/li\u003e\u003cli\u003eUNIX/Linux, Web Services e AWS.\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eLocal de trabalho\u003c/h3\u003e\u003cp\u003eVaga presencial em São Paulo, São Paulo, Brasil.\u003c/p\u003e\u003ch3\u003eObservação\u003c/h3\u003e\u003cp\u003eA descrição detalhada de responsabilidades, requisitos e benefícios não foi fornecida no anúncio original.\u003c/p\u003e","title":"Engenheiro(a) de Software, IES LATECH \u0026 GIS"},{"content":"O que é Sealed Class em Kotlin? Uma sealed class em Kotlin define uma hierarquia restrita de tipos. Isso significa que todas as subclasses possíveis são conhecidas em tempo de compilação. É como um enum turbinado — cada subtipo pode ter propriedades e comportamentos diferentes.\nA grande vantagem é que, ao usar when, o compilador sabe exatamente quais são os casos possíveis e avisa se você esquecer algum.\nSintaxe básica sealed class Resultado { data class Sucesso(val dados: String) : Resultado() data class Erro(val mensagem: String, val codigo: Int) : Resultado() object Carregando : Resultado() } Cada subclasse pode ter seus próprios campos e lógica. Diferente de um enum, onde cada valor é uma instância única, aqui cada subtipo pode carregar dados distintos.\nUsando com when A mágica acontece quando você combina sealed class com when:\nfun tratarResultado(resultado: Resultado): String { return when (resultado) { is Resultado.Sucesso -\u0026gt; \u0026#34;Deu certo: ${resultado.dados}\u0026#34; is Resultado.Erro -\u0026gt; \u0026#34;Erro ${resultado.codigo}: ${resultado.mensagem}\u0026#34; is Resultado.Carregando -\u0026gt; \u0026#34;Aguarde...\u0026#34; } } Repare que não precisa de else. O compilador sabe que esses são todos os casos possíveis. Se amanhã você adicionar um novo subtipo, o compilador vai apontar todos os lugares onde falta tratar o novo caso.\nExemplo prático com estado de tela sealed class EstadoTela { object Inicial : EstadoTela() data class Conteudo(val itens: List\u0026lt;String\u0026gt;) : EstadoTela() data class FalhaConexao(val tentativas: Int) : EstadoTela() } fun renderizar(estado: EstadoTela) { when (estado) { is EstadoTela.Inicial -\u0026gt; println(\u0026#34;Carregando tela inicial...\u0026#34;) is EstadoTela.Conteudo -\u0026gt; println(\u0026#34;Exibindo ${estado.itens.size} itens\u0026#34;) is EstadoTela.FalhaConexao -\u0026gt; println(\u0026#34;Falha! Tentativa ${estado.tentativas}\u0026#34;) } } Sealed class com comportamento As subclasses de uma sealed class podem ter métodos próprios e até implementar interfaces diferentes:\nsealed class Pagamento { abstract fun processar(): String data class CartaoCredito( val numero: String, val parcelas: Int ) : Pagamento() { override fun processar(): String { val ultimosDigitos = numero.takeLast(4) return \u0026#34;Cartão ****$ultimosDigitos em ${parcelas}x\u0026#34; } } data class Pix(val chave: String) : Pagamento() { override fun processar(): String { return \u0026#34;PIX para chave $chave\u0026#34; } } data class Boleto(val codigoBarras: String, val vencimento: String) : Pagamento() { override fun processar(): String { return \u0026#34;Boleto com vencimento em $vencimento\u0026#34; } } object Dinheiro : Pagamento() { override fun processar() = \u0026#34;Pagamento em dinheiro\u0026#34; } } fun finalizarCompra(pagamento: Pagamento) { println(\u0026#34;Processando: ${pagamento.processar()}\u0026#34;) } fun main() { finalizarCompra(Pagamento.CartaoCredito(\u0026#34;1234567890123456\u0026#34;, 3)) finalizarCompra(Pagamento.Pix(\u0026#34;karina@email.com\u0026#34;)) finalizarCompra(Pagamento.Boleto(\u0026#34;12345.67890\u0026#34;, \u0026#34;2026-04-15\u0026#34;)) finalizarCompra(Pagamento.Dinheiro) } Sealed interface (Kotlin 1.5+) A partir do Kotlin 1.5, você pode usar sealed interface para criar hierarquias seladas com mais flexibilidade, permitindo que uma classe implemente múltiplas sealed interfaces:\nsealed interface Erro { val mensagem: String } sealed interface Recuperavel { fun tentar(): Boolean } data class ErroDeRede( override val mensagem: String, val codigo: Int ) : Erro, Recuperavel { override fun tentar(): Boolean { println(\u0026#34;Tentando reconexão...\u0026#34;) return codigo != 404 } } data class ErroDeValidacao( override val mensagem: String, val campo: String ) : Erro { // Não é recuperável } fun tratarErro(erro: Erro) { println(\u0026#34;Erro: ${erro.mensagem}\u0026#34;) if (erro is Recuperavel) { val sucesso = erro.tentar() println(\u0026#34;Recuperação: ${if (sucesso) \u0026#34;OK\u0026#34; else \u0026#34;falhou\u0026#34;}\u0026#34;) } } Quando usar? Sealed classes são ideais para modelar estados finitos: resultados de operações, estados de UI, eventos de navegação e respostas de rede. Sempre que você tiver um conjunto fechado de possibilidades, pense em sealed class.\nCasos de Uso no Mundo Real Gerenciamento de estado de UI: em aplicações Android com MVVM ou MVI, sealed classes representam os diferentes estados da tela (carregando, sucesso, erro), garantindo que todos os estados sejam tratados na camada de apresentação. Resultado de operações de rede: modelar respostas HTTP como Sucesso(dados), Erro(código, mensagem) e SemConexao, forçando o tratamento de todos os cenários possíveis. Eventos de navegação: representar destinos e ações de navegação como subtipos selados, garantindo que rotas novas sejam tratadas em todo o código de navegação. Processamento de comandos: em arquiteturas orientadas a eventos, sealed classes representam os diferentes comandos que um sistema pode receber, com o compilador garantindo que nenhum comando fique sem tratamento. Boas Práticas Use object para subtipos sem dados (como Carregando ou Vazio) e data class para subtipos que carregam informações. Isso aproveita ao máximo os recursos do Kotlin. Prefira sealed interface quando precisar que uma classe participe de múltiplas hierarquias seladas. Sealed interfaces são mais flexíveis que sealed classes. Evite o branch else em expressões when com sealed classes. O else esconde a adição de novos subtipos, anulando a principal vantagem da sealed class. Mantenha a hierarquia selada no mesmo arquivo ou pacote (desde Kotlin 1.5, subclasses podem estar no mesmo pacote). Isso facilita a visualização de todos os casos possíveis. Use sealed classes para modelar domínio, não para lógica de infraestrutura. Elas brilham quando representam conceitos do negócio com um conjunto finito de variações. Erros Comuns Adicionar else no when: ao usar else, o compilador não avisa quando um novo subtipo é adicionado. Isso elimina a principal vantagem de usar sealed class e pode causar bugs silenciosos. Criar hierarquias muito profundas: sealed classes dentro de sealed classes criam complexidade desnecessária. Mantenha a hierarquia plana sempre que possível. Confundir sealed class com enum: enums são para valores fixos e simples (como dias da semana). Sealed classes são para tipos com dados e comportamentos diferentes. Usar enum quando precisa de sealed class limita o modelo. Esquecer de tratar novos subtipos: ao adicionar um novo subtipo à sealed class, todos os when sem else vão parar de compilar. Isso é uma vantagem, não um problema. Trate cada caso conscientemente. Definir subclasses fora do pacote: subclasses de sealed classes devem estar no mesmo pacote (módulo, até Kotlin 1.4). Definir fora causa erro de compilação e frustra o propósito da restrição. Perguntas Frequentes Qual a diferença entre sealed class e enum? Enums têm um número fixo de instâncias, e cada instância é um singleton. Sealed classes permitem múltiplas instâncias de cada subtipo, e cada subtipo pode ter propriedades e construtores diferentes. Use enum para valores simples e sealed class para tipos complexos.\nPosso herdar de uma sealed class fora do mesmo módulo? Não. Todas as subclasses de uma sealed class devem estar no mesmo módulo de compilação (e no mesmo pacote a partir do Kotlin 1.5). Essa restrição é o que permite ao compilador conhecer todos os subtipos em tempo de compilação.\nSealed class pode ter construtor? Sim. Sealed classes podem ter construtores com parâmetros, e as subclasses precisam chamá-los. Porém, o construtor de uma sealed class é sempre protected por padrão (ou private).\nQuando usar sealed interface em vez de sealed class? Use sealed interface quando precisar que um tipo implemente múltiplas hierarquias seladas (herança múltipla de interfaces). Use sealed class quando quiser compartilhar estado ou implementação entre os subtipos.\nTermos Relacionados Object — usado como subtipo de sealed class quando não há dados associados Data Class — o tipo mais comum de subtipo em hierarquias seladas Enum — alternativa mais simples para conjuntos fixos de valores When — expressão que se beneficia diretamente da exaustividade de sealed classes Interface — base para sealed interfaces introduzidas no Kotlin 1.5 ","permalink":"https://kotlin.dev.br/glossario/sealed-class/","summary":"\u003ch2 id=\"o-que-é-sealed-class-em-kotlin\"\u003eO que é Sealed Class em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUma \u003ccode\u003esealed class\u003c/code\u003e em Kotlin define uma \u003cstrong\u003ehierarquia restrita de tipos\u003c/strong\u003e. Isso significa que todas as subclasses possíveis são conhecidas em tempo de compilação. É como um enum turbinado — cada subtipo pode ter propriedades e comportamentos diferentes.\u003c/p\u003e\n\u003cp\u003eA grande vantagem é que, ao usar \u003ccode\u003ewhen\u003c/code\u003e, o compilador sabe exatamente quais são os casos possíveis e avisa se você esquecer algum.\u003c/p\u003e\n\u003ch3 id=\"sintaxe-básica\"\u003eSintaxe básica\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003esealed\u003c/span\u003e \u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eResultado\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003edata\u003c/span\u003e \u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eSucesso\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003edados\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eResultado\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003edata\u003c/span\u003e \u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eErro\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003emensagem\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003ecodigo\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eInt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eResultado\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eobject\u003c/span\u003e \u003cspan class=\"nc\"\u003eCarregando\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eResultado\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eCada subclasse pode ter seus próprios campos e lógica. Diferente de um \u003ccode\u003eenum\u003c/code\u003e, onde cada valor é uma instância única, aqui cada subtipo pode carregar dados distintos.\u003c/p\u003e","title":"Sealed Class em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é class em Kotlin? A palavra-chave class em Kotlin é usada para definir classes, que sao a base da programacao orientada a objetos. Uma classe funciona como um molde para criar objetos, agrupando propriedades e comportamentos relacionados.\nSe você vem do Java, vai adorar a quantidade de código que Kotlin elimina. O que levaria dezenas de linhas em Java, em Kotlin fica resolvido em poucas.\nPense em uma classe como a receita de um bolo: ela descreve os ingredientes (propriedades) é o modo de preparo (métodos). Cada bolo que você faz seguindo a receita é uma instancia daquela classe. A receita em si não e comestivel, mas cada bolo criado a partir dela e.\nSintaxe básica class Pessoa(val nome: String, var idade: Int) fun main() { val pessoa = Pessoa(\u0026#34;Rafael\u0026#34;, 28) println(\u0026#34;${pessoa.nome} tem ${pessoa.idade} anos.\u0026#34;) pessoa.idade = 29 // idade e var, pode alterar } O construtor primario já vai direto na declaracao da classe, entre parenteses. As propriedades val e var sao declaradas ali mesmo \u0026ndash; sem precisar de campos separados, getters ou setters.\nMetodos e inicialização Voce pode adicionar funções dentro da classe e usar o bloco init para lógica de inicialização:\nclass ContaBancaria(val titular: String, var saldo: Double) { init { require(saldo \u0026gt;= 0) { \u0026#34;Saldo inicial nao pode ser negativo\u0026#34; } } fun depositar(valor: Double) { saldo += valor println(\u0026#34;Deposito de R$ $valor realizado. Saldo: R$ $saldo\u0026#34;) } fun sacar(valor: Double) { if (valor \u0026lt;= saldo) { saldo -= valor println(\u0026#34;Saque de R$ $valor realizado. Saldo: R$ $saldo\u0026#34;) } else { println(\u0026#34;Saldo insuficiente!\u0026#34;) } } } Construtores secundarios Alem do construtor primario, da pra ter construtores secundarios usando constructor:\nclass Produto(val nome: String, val preco: Double) { constructor(nome: String) : this(nome, 0.0) } Heranca Por padrão, classes em Kotlin sao final \u0026ndash; não podem ser herdadas. Para permitir heranca, e preciso usar o modificador open:\nopen class Animal(val nome: String) class Cachorro(nome: String, val raca: String) : Animal(nome) Classes em Kotlin sao diretas ao ponto. Menos boilerplate, mais produtividade.\nClasse com propriedades computadas e backing field Nem toda propriedade precisa ser um simples campo armazenado. Voce pode criar propriedades com getters e setters customizados:\nclass Temperatura(celsius: Double) { var celsius: Double = celsius set(valor) { require(valor \u0026gt;= -273.15) { \u0026#34;Temperatura abaixo do zero absoluto\u0026#34; } field = valor } val fahrenheit: Double get() = celsius * 9.0 / 5.0 + 32 val kelvin: Double get() = celsius + 273.15 override fun toString(): String { return \u0026#34;%.1f C / %.1f F / %.1f K\u0026#34;.format(celsius, fahrenheit, kelvin) } } fun main() { val temp = Temperatura(25.0) println(temp) // 25.0 C / 77.0 F / 298.1 K temp.celsius = 100.0 println(temp) // 100.0 C / 212.0 F / 373.1 K } Classe com companion object e factory methods O companion object permite criar membros associados a classe (similares a membros estaticos do Java):\nclass Conexao private constructor( val host: String, val porta: Int, val usarSsl: Boolean ) { companion object { fun producao() = Conexao(\u0026#34;api.exemplo.com\u0026#34;, 443, true) fun desenvolvimento() = Conexao(\u0026#34;localhost\u0026#34;, 8080, false) fun deTeste() = Conexao(\u0026#34;localhost\u0026#34;, 9090, false) } fun url(): String { val protocolo = if (usarSsl) \u0026#34;https\u0026#34; else \u0026#34;http\u0026#34; return \u0026#34;$protocolo://$host:$porta\u0026#34; } } fun main() { val conn = Conexao.producao() println(conn.url()) // https://api.exemplo.com:443 val dev = Conexao.desenvolvimento() println(dev.url()) // http://localhost:8080 } Classe com delegacao de interface Kotlin suporta delegacao nativamente, permitindo que uma classe delegue a implementação de uma interface para outro objeto:\ninterface Logger { fun log(mensagem: String) } class ConsoleLogger : Logger { override fun log(mensagem: String) { println(\u0026#34;[LOG] $mensagem\u0026#34;) } } class Servico(logger: Logger) : Logger by logger { fun executar() { log(\u0026#34;Servico iniciado\u0026#34;) // delegado ao ConsoleLogger // logica do servico log(\u0026#34;Servico finalizado\u0026#34;) } } Casos de Uso no Mundo Real Modelagem de dominio: classes representam entidades do negócio como Pedido, Cliente, Produto. Para entidades focadas em dados, considere data classes. Servicos e controladores: no Spring Boot e Ktor, classes encapsulam a lógica de negocios e endpoints da API. ViewModels no Android: classes que estendem ViewModel gerenciam o estado da UI e sobrevivem a mudancas de configuração. Wrappers e adaptadores: classes que encapsulam APIs externas, oferecendo uma interface mais limpa para o restante do código. Builders: classes que implementam o padrão builder para construcao de objetos complexos, especialmente úteis em DSLs Kotlin. Boas Praticas Prefira data class quando a classe serve principalmente para armazenar dados, pois ela gera equals(), hashCode(), toString() e copy() automaticamente. Use val para propriedades sempre que possível, favorecendo imutabilidade. Mantenha classes pequenas e focadas em uma única responsabilidade. Se uma classe tem muitos métodos, considere dividi-la. Aproveite valores padrão em parametros do construtor em vez de criar múltiplos construtores secundarios. Use private constructor com factory methods no companion object quando precisar controlar como instancias sao criadas. Erros Comuns Esquecer open para heranca: diferente do Java, classes Kotlin sao final por padrão. Tentar herdar de uma classe sem open causa erro de compilação. Confundir val e var no construtor: val cria uma propriedade somente leitura, var permite alteracao. Parametros sem val/var no construtor primario sao apenas parametros, não propriedades da classe. Bloco init com lógica pesada: o bloco init roda toda vez que a classe e instanciada. Evite colocar operações de rede, leitura de arquivos ou lógica demorada nele. Nao usar data class quando apropriado: criar uma classe normal e implementar equals(), hashCode() e toString() manualmente quando uma data class faria tudo automaticamente. Perguntas Frequentes Qual a diferenca entre class e data class? Uma class normal não gera automaticamente equals(), hashCode(), toString() nem copy(). Uma data class gera todos esses métodos com base nas propriedades do construtor primario. Use data class para objetos que representam dados.\nPosso ter uma classe sem corpo? Sim. class Vazia e perfeitamente válido em Kotlin. Tambem e possível ter uma classe só com construtor: class Ponto(val x: Int, val y: Int).\nQual a diferenca entre class e object? class e um molde para criar múltiplas instancias. object cria uma única instancia (singleton). Use object quando você precisa de apenas uma instancia em todo o aplicativo.\nQuando usar abstract class vs interface? Use abstract class quando subclasses compartilham estado (propriedades com valor) e lógica de construtor. Use interface quando você precisa apenas de um contrato, especialmente se a classe já herda de outra (Kotlin não suporta heranca multipla de classes, mas suporta múltiplas interfaces).\n","permalink":"https://kotlin.dev.br/glossario/class/","summary":"\u003ch2 id=\"o-que-é-class-em-kotlin\"\u003eO que é \u003ccode\u003eclass\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eA palavra-chave \u003ccode\u003eclass\u003c/code\u003e em Kotlin é usada para \u003cstrong\u003edefinir classes\u003c/strong\u003e, que sao a base da programacao orientada a objetos. Uma classe funciona como um molde para criar objetos, agrupando propriedades e comportamentos relacionados.\u003c/p\u003e\n\u003cp\u003eSe você vem do Java, vai adorar a quantidade de código que Kotlin elimina. O que levaria dezenas de linhas em Java, em Kotlin fica resolvido em poucas.\u003c/p\u003e\n\u003cp\u003ePense em uma classe como a receita de um bolo: ela descreve os ingredientes (propriedades) é o modo de preparo (métodos). Cada bolo que você faz seguindo a receita é uma instancia daquela classe. A receita em si não e comestivel, mas cada bolo criado a partir dela e.\u003c/p\u003e","title":"class em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é fun em Kotlin? A palavra-chave fun é usada para declarar funções em Kotlin. Toda função na linguagem começa com fun, seguida do nome, dos parâmetros entre parênteses e, opcionalmente, do tipo de retorno.\nSe você está acostumado com Java, vai perceber que em Kotlin as funções são bem mais enxutas. Dá pra escrever bastante coisa com poucas linhas.\nSintaxe básica fun saudacao(nome: String): String { return \u0026#34;Olá, $nome! Bem-vindo ao Kotlin Brasil.\u0026#34; } fun main() { println(saudacao(\u0026#34;Karina\u0026#34;)) } Os parâmetros são declarados no formato nome: Tipo, e o tipo de retorno vem depois dos parênteses, separado por :. Se a função não retorna nada, o tipo de retorno é Unit — mas você não precisa escrever isso explicitamente.\nFunções de expressão única Quando a função tem só uma expressão, dá pra simplificar bastante usando o sinal de =:\nfun dobro(x: Int): Int = x * 2 fun saudacao(nome: String) = \u0026#34;E aí, $nome! Tudo certo?\u0026#34; Repare que na segunda função nem precisou declarar o tipo de retorno. O compilador infere sozinho que é String.\nParâmetros com valor padrão Kotlin permite definir valores padrão nos parâmetros, o que é uma mão na roda:\nfun criarUsuario(nome: String, ativo: Boolean = true): String { return \u0026#34;$nome - Ativo: $ativo\u0026#34; } fun main() { println(criarUsuario(\u0026#34;Ana\u0026#34;)) // Ana - Ativo: true println(criarUsuario(\u0026#34;João\u0026#34;, false)) // João - Ativo: false } Isso elimina a necessidade de vários overloads que seriam obrigatórios em Java.\nFunções são cidadãs de primeira classe Em Kotlin, funções podem ser armazenadas em variáveis, passadas como argumento e retornadas por outras funções. Isso abre as portas para programação funcional de um jeito muito natural.\nArgumentos nomeados Uma funcionalidade poderosa do Kotlin é chamar funções usando o nome dos parâmetros. Isso melhora a legibilidade, especialmente em funções com muitos parâmetros:\nfun criarPedido( produto: String, quantidade: Int, desconto: Double = 0.0, frete: Boolean = true ): String { return \u0026#34;$quantidade x $produto (desconto: $desconto, frete: $frete)\u0026#34; } fun main() { println(criarPedido(produto = \u0026#34;Teclado\u0026#34;, quantidade = 2, frete = false)) // 2 x Teclado (desconto: 0.0, frete: false) } Com argumentos nomeados, você pode pular parâmetros com valor padrão e chamar em qualquer ordem, tornando o código mais legível e menos propenso a erros.\nFunções de extensão Kotlin permite adicionar funções a classes existentes sem herança usando extension functions:\nfun String.contarPalavras(): Int { return this.trim().split(\u0026#34;\\\\s+\u0026#34;.toRegex()).size } fun main() { val frase = \u0026#34;Kotlin e uma linguagem moderna\u0026#34; println(frase.contarPalavras()) // 5 } A função contarPalavras se comporta como se fosse um método nativo da classe String, mas foi definida fora dela. Esse recurso é amplamente usado em bibliotecas Kotlin para estender APIs existentes de forma elegante.\nFunções locais Você pode declarar funções dentro de outras funções para encapsular lógica auxiliar:\nfun processarPedido(itens: List\u0026lt;String\u0026gt;): String { fun validar(item: String): Boolean { return item.isNotBlank() \u0026amp;\u0026amp; item.length \u0026lt;= 100 } val validos = itens.filter { validar(it) } return \u0026#34;Processando ${validos.size} itens validos\u0026#34; } Funções locais têm acesso às variáveis da função externa, o que as torna práticas para lógica que só faz sentido naquele contexto.\nCasos de Uso no Mundo Real Endpoints de API REST: cada endpoint em frameworks como Ktor ou Spring é definido como uma função, aproveitando parâmetros com valor padrão para configurações opcionais como paginação e filtros. Transformação de dados: funções de expressão única são ideais para mapear DTOs em entidades de domínio, mantendo o código de conversão conciso e fácil de localizar. Validação de formulários: funções com parâmetros nomeados facilitam a criação de validadores reutilizáveis onde cada regra é configurável e legível. Funções utilitárias em projetos Android: extension functions permitem adicionar métodos como View.esconder() ou String.formatarCPF() sem criar classes utilitárias estáticas. Boas Práticas Prefira funções de expressão única quando o corpo da função cabe em uma linha. Isso reduz ruído visual e torna o código mais direto. Use parâmetros com valor padrão em vez de criar múltiplos overloads. O resultado é mais limpo e mais fácil de manter. Nomeie funções com verbos que descrevam a ação: calcularTotal, buscarUsuario, validarEmail. Nomes claros dispensam comentários. Mantenha funções curtas e com uma única responsabilidade. Se a função faz mais de uma coisa, divida em funções menores. Declare o tipo de retorno explicitamente em funções públicas de APIs e bibliotecas, mesmo quando o compilador pode inferir, para melhorar a documentação do código. Erros Comuns Esquecer que parâmetros com valor padrão devem vir por último: ao misturar parâmetros obrigatórios e opcionais, coloque os opcionais no final. Caso contrário, será necessário usar argumentos nomeados em toda chamada. Retornar Unit explicitamente quando não é necessário: funções que não retornam valor não precisam de return Unit nem de declarar : Unit. Basta omitir. Criar extension functions com nomes que conflitam com métodos da classe: se a classe já tem um método com o mesmo nome e assinatura, o método da classe sempre tem prioridade, e a extension function nunca será chamada. Não usar @JvmOverloads ao expor funções com valores padrão para código Java: sem essa anotação, o Java só enxerga a versão com todos os parâmetros, perdendo os benefícios dos defaults. Declarar funções longas de expressão única: se a expressão é complexa ou ocupa múltiplas linhas, use a forma com corpo e return. A forma de expressão única deve ser reservada para lógica simples. Perguntas Frequentes Qual a diferença entre fun em Kotlin e def em Python? Ambas declaram funções, mas fun exige tipos explícitos para os parâmetros (inferência funciona apenas para o retorno em expressões únicas). Kotlin é estaticamente tipado, enquanto Python é dinamicamente tipado.\nPosso criar funções fora de classes em Kotlin? Sim. Kotlin suporta funções de nível superior (top-level functions) que não pertencem a nenhuma classe. Elas são compiladas como métodos estáticos de uma classe gerada automaticamente.\nO que acontece se eu declarar uma função sem tipo de retorno? Se você usa a forma com corpo (chaves), o tipo de retorno padrão é Unit. Se usa a forma de expressão única, o compilador infere o tipo a partir da expressão.\nPosso sobrecarregar funções em Kotlin? Sim. Kotlin suporta sobrecarga (overload) de funções com o mesmo nome mas assinaturas diferentes. No entanto, parâmetros com valor padrão frequentemente eliminam a necessidade de overloads.\nTermos Relacionados Lambda — funções anônimas que complementam o uso de fun Higher-Order Function — funções que recebem ou retornam outras funções declaradas com fun Inline — modificador que otimiza funções que recebem lambdas Interface — contratos que podem declarar funções abstratas implementadas com fun ","permalink":"https://kotlin.dev.br/glossario/fun/","summary":"\u003ch2 id=\"o-que-é-fun-em-kotlin\"\u003eO que é \u003ccode\u003efun\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eA palavra-chave \u003ccode\u003efun\u003c/code\u003e é usada para \u003cstrong\u003edeclarar funções\u003c/strong\u003e em Kotlin. Toda função na linguagem começa com \u003ccode\u003efun\u003c/code\u003e, seguida do nome, dos parâmetros entre parênteses e, opcionalmente, do tipo de retorno.\u003c/p\u003e\n\u003cp\u003eSe você está acostumado com Java, vai perceber que em Kotlin as funções são bem mais enxutas. Dá pra escrever bastante coisa com poucas linhas.\u003c/p\u003e\n\u003ch3 id=\"sintaxe-básica\"\u003eSintaxe básica\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003esaudacao\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enome\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Olá, \u003c/span\u003e\u003cspan class=\"si\"\u003e$nome\u003c/span\u003e\u003cspan class=\"s2\"\u003e! Bem-vindo ao Kotlin Brasil.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esaudacao\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Karina\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eOs parâmetros são declarados no formato \u003ccode\u003enome: Tipo\u003c/code\u003e, e o tipo de retorno vem depois dos parênteses, separado por \u003ccode\u003e:\u003c/code\u003e. Se a função não retorna nada, o tipo de retorno é \u003ccode\u003eUnit\u003c/code\u003e — mas você não precisa escrever isso explicitamente.\u003c/p\u003e","title":"fun em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é val em Kotlin? A palavra-chave val em Kotlin serve para declarar variáveis somente leitura, ou seja, uma vez que você atribui um valor a ela, não dá pra mudar depois. É como se fosse uma constante local — você define o valor e pronto, ele fica fixo dali em diante.\nSe você já programou em Java, pode pensar no val como o equivalente ao final. A diferença é que em Kotlin, usar val é muito mais natural e incentivado pela própria linguagem.\nPor que usar val? A grande sacada de usar val é tornar o código mais previsível e seguro. Quando você garante que um valor não vai mudar, fica muito mais fácil de entender o que tá acontecendo no programa. Menos bugs, menos dor de cabeça.\nNa prática, a recomendação da comunidade Kotlin é: sempre comece com val. Só troque pra var se realmente precisar alterar o valor depois.\nExemplo prático fun main() { val nome = \u0026#34;Kotlin Brasil\u0026#34; val ano = 2026 println(\u0026#34;Bem-vindo ao $nome! Estamos em $ano.\u0026#34;) // Isso aqui daria erro de compilacao: // nome = \u0026#34;Outro nome\u0026#34; // Val cannot be reassigned } Perceba que o compilador já infere o tipo automaticamente. O nome é uma String e o ano é um Int, sem precisar declarar isso explicitamente.\nval não significa imutável em tudo Um ponto importante: val garante que a referência não muda, mas o conteúdo do objeto pode mudar. Por exemplo, se você declara uma lista mutável com val, não pode reatribuir a variável, mas pode adicionar itens na lista.\nval frutas = mutableListOf(\u0026#34;Manga\u0026#34;, \u0026#34;Acerola\u0026#34;) frutas.add(\u0026#34;Goiaba\u0026#34;) // Funciona! // frutas = mutableListOf(\u0026#34;Banana\u0026#34;) // Erro! Não pode reatribuir Essa distinção é fundamental pra quem tá começando com Kotlin. Usar val sempre que possível é uma prática que vai deixar seu código mais limpo e confiável.\nval com tipos explícitos e inicialização tardia Em algumas situações, você pode querer declarar o tipo explicitamente ou inicializar o val em momentos diferentes dentro do mesmo bloco.\nfun calcularDesconto(preco: Double, porcentagem: Int): String { val desconto: Double val mensagem: String if (porcentagem \u0026gt; 0) { desconto = preco * porcentagem / 100 mensagem = \u0026#34;Desconto de R$ ${\u0026#34;%.2f\u0026#34;.format(desconto)}\u0026#34; } else { desconto = 0.0 mensagem = \u0026#34;Sem desconto aplicado\u0026#34; } return mensagem } fun main() { println(calcularDesconto(150.0, 10)) // Desconto de R$ 15,00 println(calcularDesconto(80.0, 0)) // Sem desconto aplicado } O compilador do Kotlin permite que um val seja atribuído em branches diferentes de um if ou when, desde que ele seja atribuído exatamente uma vez em todos os caminhos possíveis.\nval em data classes e propriedades O val é amplamente usado em data class para criar objetos imutáveis, um padrão muito valorizado em programação funcional e em aplicações concorrentes.\ndata class Produto( val nome: String, val preco: Double, val categoria: String ) fun main() { val notebook = Produto(\u0026#34;Notebook\u0026#34;, 3500.0, \u0026#34;Eletrônicos\u0026#34;) println(notebook) // Produto(nome=Notebook, preco=3500.0, categoria=Eletrônicos) // Para \u0026#34;alterar\u0026#34;, crie uma cópia com copy() val comDesconto = notebook.copy(preco = 2990.0) println(comDesconto) // Produto(nome=Notebook, preco=2990.0, categoria=Eletrônicos) } Casos de Uso no Mundo Real Configurações de aplicação: Valores como URL base da API, chaves de configuração e timeouts são naturalmente imutáveis. Declará-los com val garante que nenhuma parte do código vai alterar esses valores acidentalmente durante a execução. Resultados de consultas ao banco: Quando você busca dados do banco ou de uma API, o resultado retornado não deve ser modificado. Usar val para armazenar esses resultados evita alterações involuntárias que poderiam causar inconsistências. Injeção de dependências: Em frameworks como Koin e Dagger/Hilt, as dependências injetadas são declaradas com val. Uma vez injetado, o serviço ou repositório não deve ser substituído durante o ciclo de vida do componente. Parâmetros de funções em Kotlin: Todos os parâmetros de funções em Kotlin são implicitamente val. Você não pode reatribuí-los dentro do corpo da função, o que é uma decisão de design da linguagem que evita efeitos colaterais inesperados. Boas Práticas Comece sempre com val: Essa é a regra número um. Declare tudo como val primeiro. Só mude para var se o compilador indicar que você precisa reatribuir o valor. Essa abordagem é chamada de \u0026ldquo;immutability by default\u0026rdquo;. Combine val com coleções imutáveis: Use listOf(), mapOf() e setOf() junto com val para garantir imutabilidade total. Usar val com mutableListOf() protege apenas a referência, não o conteúdo. Use val em propriedades de classe: Propriedades declaradas com val em classes são thread-safe para leitura, pois não podem ser reatribuídas após a construção do objeto. Prefira val com expressões when e if: Em Kotlin, if e when são expressões que retornam valor. Use val resultado = when { ... } em vez de declarar um var e atribuir dentro de cada branch. Considere const val para constantes de compilação: Quando o valor é uma primitiva ou String conhecida em tempo de compilação, use const val no companion object para otimizar a performance. Erros Comuns Achar que val torna o objeto completamente imutável: Como mostrado acima, val protege apenas a referência. Se o objeto apontado é mutável (como MutableList), seu conteúdo interno ainda pode ser alterado. Para imutabilidade total, combine val com tipos imutáveis. Usar var por hábito de outras linguagens: Quem vem de Java, JavaScript ou Python tende a usar var para tudo. Em Kotlin, isso desperdiça uma das maiores vantagens da linguagem. O IntelliJ IDEA inclusive mostra um aviso quando um var nunca é reatribuído. Confundir val com const val: val é avaliado em tempo de execução, enquanto const val é avaliado em tempo de compilação. const val só pode ser usado com tipos primitivos e String em objetos ou companion objects. Não usar val em loops for: A variável de iteração em um for já é implicitamente val. Tentar reatribuí-la dentro do loop causa erro de compilação, o que é o comportamento correto e esperado. Declarar val sem inicializar fora de condicionais: Um val deve ser inicializado antes de ser usado. Se você declará-lo sem valor e esquecer de atribuir em algum branch do código, o compilador vai apontar o erro. Perguntas Frequentes Qual a diferença entre val e const val? val pode receber qualquer valor em tempo de execução, incluindo resultados de funções e objetos complexos. const val é restrito a tipos primitivos e String, precisa ser declarado em companion objects ou top-level, e o valor é embutido diretamente no bytecode em tempo de compilação.\nval é a mesma coisa que final em Java? Conceitualmente sim, ambos impedem a reatribuição da variável. A diferença é que em Kotlin, val é a forma padrão e incentivada de declarar variáveis, enquanto final em Java é uma anotação adicional que poucos desenvolvedores usam consistentemente.\nPosso usar val com lateinit? Não. lateinit só pode ser usado com var, pois a variável precisa ser atribuída depois da declaração, o que contradiz a natureza somente-leitura do val. Para inicialização tardia com val, use by lazy.\nval torna meu código mais lento? Não. Na verdade, o compilador pode fazer otimizações mais agressivas quando sabe que um valor não vai mudar. Além disso, val não gera overhead de runtime — no bytecode, a diferença é simplesmente a ausência de um método setter.\nTermos Relacionados var — A contraparte mutável de val, usada quando o valor precisa ser reatribuído. Data Class — Classes de dados que usam val para criar objetos imutáveis. Null Safety — Sistema de tipos nulos do Kotlin, frequentemente combinado com val para variáveis seguras. when — Expressão que retorna valor e combina perfeitamente com val para atribuição condicional. ","permalink":"https://kotlin.dev.br/glossario/val/","summary":"\u003ch2 id=\"o-que-é-val-em-kotlin\"\u003eO que é \u003ccode\u003eval\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eA palavra-chave \u003ccode\u003eval\u003c/code\u003e em Kotlin serve para declarar \u003cstrong\u003evariáveis somente leitura\u003c/strong\u003e, ou seja, uma vez que você atribui um valor a ela, não dá pra mudar depois. É como se fosse uma constante local — você define o valor e pronto, ele fica fixo dali em diante.\u003c/p\u003e\n\u003cp\u003eSe você já programou em Java, pode pensar no \u003ccode\u003eval\u003c/code\u003e como o equivalente ao \u003ccode\u003efinal\u003c/code\u003e. A diferença é que em Kotlin, usar \u003ccode\u003eval\u003c/code\u003e é muito mais natural e incentivado pela própria linguagem.\u003c/p\u003e","title":"val em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é var em Kotlin? A palavra-chave var em Kotlin serve para declarar variáveis mutáveis, ou seja, variáveis cujo valor pode ser alterado depois da atribuição inicial. Se você precisa de um valor que vai mudar ao longo da execução do programa, var é o caminho.\nEnquanto val trava o valor, var te dá liberdade para reatribuir quantas vezes quiser — desde que o novo valor seja do mesmo tipo.\nQuando usar var? A regra de ouro é simples: só use var quando realmente precisar alterar o valor. Contadores, acumuladores, estados que mudam durante a execução — esses são casos clássicos onde var faz sentido.\nNão saia usando var em tudo só por costume. O compilador do Kotlin inclusive sugere trocar pra val quando detecta que a variável nunca é reatribuída.\nExemplo prático fun main() { var contador = 0 for (i in 1..5) { contador += i } println(\u0026#34;Soma total: $contador\u0026#34;) // Soma total: 15 var status = \u0026#34;pendente\u0026#34; println(\u0026#34;Status: $status\u0026#34;) status = \u0026#34;concluído\u0026#34; println(\u0026#34;Status: $status\u0026#34;) } No exemplo acima, tanto contador quanto status precisam mudar de valor, então faz todo sentido usar var.\nTipo é fixo, mesmo com var Um detalhe que pega muita gente: mesmo usando var, o tipo da variável não muda. Se você declarou como Int, vai ser Int pra sempre.\nvar idade = 25 // idade = \u0026#34;vinte e cinco\u0026#34; // Erro! Não pode mudar o tipo var mensagem = \u0026#34;Olá\u0026#34; mensagem = \u0026#34;Tchau\u0026#34; // Tudo certo, continua sendo String Kotlin é uma linguagem de tipagem estática, então o tipo é definido na declaração e ponto final. O var muda o valor, não o tipo.\nvar vs val Na dúvida, comece sempre com val. Se o compilador reclamar que você tá tentando reatribuir, aí sim troque pra var. Essa abordagem deixa o código mais seguro e fácil de manter.\nvar com propriedades customizadas Uma funcionalidade poderosa do Kotlin é a possibilidade de definir getters e setters customizados para propriedades var. Isso permite adicionar válidação ou lógica extra na atribuição.\nclass ContaBancaria(saldoInicial: Double) { var saldo: Double = saldoInicial private set // Só a própria classe pode alterar var limite: Double = 1000.0 set(value) { if (value \u0026gt;= 0) { field = value } else { println(\u0026#34;Limite nao pode ser negativo\u0026#34;) } } fun depositar(valor: Double) { if (valor \u0026gt; 0) saldo += valor } fun sacar(valor: Double): Boolean { return if (valor \u0026lt;= saldo + limite) { saldo -= valor true } else { false } } } fun main() { val conta = ContaBancaria(500.0) conta.depositar(200.0) println(\u0026#34;Saldo: ${conta.saldo}\u0026#34;) // Saldo: 700.0 conta.limite = -100.0 // Limite nao pode ser negativo println(\u0026#34;Limite: ${conta.limite}\u0026#34;) // Limite: 1000.0 } var com lateinit Quando você sabe que uma variável será inicializada antes de ser usada, mas não pode atribuir o valor no momento da declaração, lateinit var é a solução. Isso é muito comum em frameworks como Android e Spring.\nclass PerfilUsuario { lateinit var nome: String lateinit var email: String fun inicializar(nome: String, email: String) { this.nome = nome this.email = email } fun exibir() { if (::nome.isInitialized) { println(\u0026#34;Nome: $nome, Email: $email\u0026#34;) } else { println(\u0026#34;Perfil nao inicializado\u0026#34;) } } } fun main() { val perfil = PerfilUsuario() perfil.exibir() // Perfil nao inicializado perfil.inicializar(\u0026#34;Mariana\u0026#34;, \u0026#34;mariana@email.com\u0026#34;) perfil.exibir() // Nome: Mariana, Email: mariana@email.com } Casos de Uso no Mundo Real Estado de interface no Android: Em ViewModels e Activities, variáveis como isLoading, errorMessage e currentPage precisam mudar conforme o usuário interage. Usar var (geralmente via MutableStateFlow ou MutableLiveData) é essencial para refletir essas mudanças na tela. Contadores e acumuladores: Em processamento de dados, relatórios ou análises, contadores de iteração, somas parciais e valores acumulados precisam ser reatribuídos a cada passo. São casos onde var é indispensável. Configuração de builders: Padrões como o Builder Pattern dependem de propriedades mutáveis que são configuradas passo a passo antes de construir o objeto final. Cada chamada de método no builder altera uma propriedade var interna. Loops com condição de parada: Variáveis de controle como flags booleanas (var encontrado = false) ou variáveis de resultado que são preenchidas durante a iteração são cenários legítimos para var. Boas Práticas Minimize o escopo de variáveis var: Declare a variável o mais perto possível de onde ela é usada. Quanto menor o escopo, menor o risco de alterações inesperadas e mais fácil de rastrear mudanças. Considere alternativas funcionais: Muitas vezes, um var com loop pode ser substituído por operações funcionais como fold, reduce, map ou sumOf. Essas alternativas eliminam a necessidade de mutabilidade e tornam o código mais expressivo. Use private set para controlar acesso: Se uma propriedade var de uma classe deve ser lida externamente mas modificada apenas internamente, declare o setter como private set. Isso preserva o encapsulamento. Evite var em data classes: Propriedades var em data class podem causar problemas quando o objeto é usado como chave em mapas ou sets, pois o hashCode muda com a reatribuição. Prefira val e use copy() para criar versões modificadas. Prefira MutableStateFlow a var observável: Em projetos com Kotlin coroutines, usar MutableStateFlow em vez de um var simples oferece reatividade e thread-safety nativos, sem necessidade de sincronização manual. Erros Comuns Usar var por padrão: O erro mais comum de quem vem de outras linguagens é declarar tudo como var. Em Kotlin, a abordagem correta é o inverso: comece com val e só mude para var quando realmente precisar reatribuir o valor. Acessar var de múltiplas threads sem sincronização: Variáveis var não são thread-safe. Se duas threads modificam a mesma variável ao mesmo tempo, você terá condições de corrida. Use AtomicInteger, Mutex ou MutableStateFlow para cenários concorrentes. Confundir reatribuição com mutação: var lista = listOf(1, 2, 3) permite reatribuir a referência (lista = listOf(4, 5)), mas não permite lista.add() porque listOf retorna uma lista imutável. Já val lista = mutableListOf(1, 2, 3) permite lista.add() mas não permite reatribuir a referência. São conceitos diferentes. Usar lateinit var com tipos primitivos: lateinit não pode ser usado com Int, Double, Boolean e outros tipos primitivos. Para esses casos, inicialize com um valor padrão ou use Delegates.notNull\u0026lt;Int\u0026gt;(). Não verificar isInitialized antes de acessar lateinit: Acessar uma variável lateinit antes de inicializá-la causa UninitializedPropertyAccessException. Sempre verifique com ::propriedade.isInitialized quando houver dúvida sobre a inicialização. Perguntas Frequentes Posso mudar o tipo de uma variável var? Não. Kotlin é uma linguagem com tipagem estática. O tipo é definido na primeira atribuição (ou explicitamente na declaração) e não pode ser alterado depois. Se você precisa armazenar tipos diferentes, considere usar Any como tipo, mas isso raramente é recomendado.\nvar é mais lento que val? Na prática, a diferença de performance é irrelevante. No entanto, val permite que o compilador faça certas otimizações (como inlining) que não são possíveis com var, já que o valor pode mudar. A escolha entre var e val deve ser baseada em semântica, não em performance.\nQuando devo usar var em vez de uma coleção mutável com val? Se você precisa substituir a coleção inteira, use var com uma coleção imutável (var lista = listOf(...)). Se precisa apenas adicionar ou remover itens, use val com uma coleção mutável (val lista = mutableListOf(...)). Evite combinar var com coleção mutável, pois isso gera ambiguidade sobre como a modificação deve ocorrer.\nÉ possível observar mudanças em uma variável var? Sim, usando Delegates.observable. Isso permite executar código toda vez que o valor da variável é alterado, o que é útil para logging, atualização de UI ou válidação.\nTermos Relacionados val — A contraparte imutável de var, usada para variáveis somente leitura. Data Class — Classes de dados onde geralmente se prefere val a var nas propriedades. Null Safety — Sistema de tipos nulos do Kotlin que se aplica tanto a var quanto a val. when — Expressão condicional que pode retornar valores para atribuição a variáveis var ou val. ","permalink":"https://kotlin.dev.br/glossario/var/","summary":"\u003ch2 id=\"o-que-é-var-em-kotlin\"\u003eO que é \u003ccode\u003evar\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eA palavra-chave \u003ccode\u003evar\u003c/code\u003e em Kotlin serve para declarar \u003cstrong\u003evariáveis mutáveis\u003c/strong\u003e, ou seja, variáveis cujo valor pode ser alterado depois da atribuição inicial. Se você precisa de um valor que vai mudar ao longo da execução do programa, \u003ccode\u003evar\u003c/code\u003e é o caminho.\u003c/p\u003e\n\u003cp\u003eEnquanto \u003ccode\u003eval\u003c/code\u003e trava o valor, \u003ccode\u003evar\u003c/code\u003e te dá liberdade para reatribuir quantas vezes quiser — desde que o novo valor seja do mesmo tipo.\u003c/p\u003e","title":"var em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"Como instalar Kotlin? Resposta rápida: a forma mais simples de instalar Kotlin é usar o IntelliJ IDEA Community Edition ou o Android Studio, porque já vêm com suporte completo a Kotlin embutido, sem configurar nada. Para quem prefere o terminal: no macOS e no Linux, instale o SDKMAN! e rode sdk install kotlin; no macOS com Homebrew, brew install kotlin também funciona; no Windows, o ideal é começar pelo IntelliJ/Android Studio (ou usar WSL com SDKMAN!). Em qualquer caso você também precisa de um JDK, de preferência o JDK 17 ou JDK 21.\nTá pronto pra botar a mão na massa? Então bora instalar o Kotlin no seu computador. Existem várias formas de fazer isso, e vou te mostrar as principais.\nComo instalar o Kotlin: escolha o caminho certo Antes do passo a passo, escolha o caminho pelo seu objetivo:\nObjetivo Melhor instalação Comando ou download Aprender Kotlin do zero IntelliJ IDEA Community Baixar em jetbrains.com/idea/download Criar app Android Android Studio Baixar em developer.android.com/studio Windows com terminal JDK 21 + Gradle ou WSL java -version e projeto Gradle Kotlin macOS/Linux no terminal SDKMAN! sdk install kotlin macOS com Homebrew Homebrew brew install kotlin Testar sem instalar Kotlin Playground play.kotlinlang.org Se você pesquisou \u0026ldquo;como instalar o Kotlin\u0026rdquo; e só quer começar rápido: instale o IntelliJ, crie um projeto Kotlin/JVM e rode o arquivo Main.kt. Se você já usa terminal, instale o JDK 21 + o SDKMAN! + o Kotlin.\nOpção 1: IntelliJ IDEA (Recomendada) A forma mais simples de começar é instalando o IntelliJ IDEA Community Edition, que é gratuito e já vem com suporte completo a Kotlin embutido:\nAcesse jetbrains.com/idea/download Baixe a Community Edition (gratuita) Instale normalmente no seu sistema operacional Abra o IntelliJ e crie um novo projeto Kotlin Pronto! Sem configuração extra, sem dor de cabeça. O IntelliJ cuida de tudo pra você.\nO IntelliJ também oferece recursos avançados como autocompletar inteligente, refatoração automatizada, depuração integrada e suporte nativo a Gradle. Para quem está começando, a experiência de desenvolvimento é muito superior a usar apenas um editor de texto simples. Ainda em dúvida sobre o editor? Veja qual é a melhor IDE para programar em Kotlin.\nOpção 2: Android Studio (Para desenvolvimento mobile) Se seu foco é Android, o Android Studio é o caminho:\nAcesse developer.android.com/studio Baixe e instale o Android Studio Ele já vem com Kotlin configurado por padrão O Android Studio é baseado no IntelliJ IDEA, então a experiência é bem parecida, mas com ferramentas extras voltadas para mobile: emulador de dispositivos, inspetor de layout, profiler de performance e integração com o Google Play. Se quiser um passo a passo detalhado, confira nosso tutorial de Kotlin com Android Studio e o guia de desenvolvimento Android.\nComo instalar o Kotlin no Windows em 2026 Para a maioria dos usuários de Windows, o caminho mais rápido e com menos erros ainda é o IntelliJ IDEA Community Edition. Ele já traz modelos de projeto Kotlin, detecta o JDK automaticamente e cria um Main.kt executável sem você precisar editar o PATH manualmente. Se o seu objetivo é Android, use o Android Studio no lugar, porque ele instala o Android SDK, o emulador e a integração com o Gradle no mesmo fluxo.\nUm setup prático no Windows fica assim:\nInstall JDK 21 from Eclipse Temurin, Microsoft Build of OpenJDK or another trusted distribution. Install IntelliJ IDEA Community. Create a new Kotlin/JVM project with Gradle. Run the generated main function from the IDE. Only after that, configure terminal usage if you really need kotlinc globally. To check the JDK from PowerShell, run:\njava -version where java Se o java -version falhar, resolva o Java antes de instalar as ferramentas do Kotlin. A maioria dos problemas de instalação do Kotlin no Windows é, na verdade, problema de JDK ou de PATH. Para quem trabalha muito na linha de comando, muitos desenvolvedores preferem WSL + SDKMAN!, porque ele acompanha as instruções de Linux/macOS e facilita a troca de versão.\nComo instalar o Kotlin no Linux em 2026 No Linux, o SDKMAN! costuma ser melhor do que os pacotes da distribuição porque entrega versões atuais do Kotlin e do Java. Algumas distribuições vêm com um compilador mais antigo, o que confunde iniciantes quando um tutorial espera recursos mais novos da linguagem. Use os pacotes da distro apenas quando você precisa de um tooling gerenciado pelo sistema em um ambiente restrito.\nFluxo recomendado no Linux:\ncurl -s \u0026#34;https://get.sdkman.io\u0026#34; | bash source \u0026#34;$HOME/.sdkman/bin/sdkman-init.sh\u0026#34; sdk install java 21-tem sdk install kotlin java -version kotlin -version Se você está montando um projeto real de backend ou Android, não dependa para sempre de um compilador global. Deixe o Gradle fixar a versão do plugin Kotlin no build.gradle.kts e use o wrapper do projeto (./gradlew), assim todo o time compila com a mesma versão. Veja também nosso tutorial de Gradle com Kotlin e a comparação Gradle Kotlin DSL vs Groovy.\nInstalar o Kotlin pela linha de comando com SDKMAN! Dica rápida: o SDKMAN! é o instalador via linha de comando mais conveniente para Kotlin no macOS e no Linux porque gerencia versões do Kotlin e do JDK no mesmo lugar. Instale o SDKMAN!, abra um novo terminal, rode sdk install kotlin e confira com kotlin -version.\nOpção 3: Linha de comando (SDKMAN!) Pra quem curte o terminal, o SDKMAN! é a forma mais prática de gerenciar o Kotlin no macOS e Linux:\n# Instalar o SDKMAN! curl -s \u0026#34;https://get.sdkman.io\u0026#34; | bash source \u0026#34;$HOME/.sdkman/bin/sdkman-init.sh\u0026#34; # Instalar o Kotlin sdk install kotlin # Verificar a instalação kotlin -version Depois de instalado, você pode compilar e rodar arquivos Kotlin direto pelo terminal:\n# Criar um arquivo echo \u0026#39;fun main() { println(\u0026#34;Kotlin instalado com sucesso!\u0026#34;) }\u0026#39; \u0026gt; ola.kt # Compilar e rodar kotlinc ola.kt -include-runtime -d ola.jar java -jar ola.jar A grande vantagem do SDKMAN! é que ele permite ter múltiplas versões do Kotlin instaladas ao mesmo tempo e alternar entre elas facilmente com sdk use kotlin \u0026lt;versão\u0026gt;. Isso é muito útil quando você trabalha em projetos que exigem versões diferentes.\nInstalar o Kotlin no macOS com Homebrew Se a sua intenção é especificamente instalar Kotlin com Homebrew no Mac, o Homebrew funciona bem para ter uma versão global do Kotlin. Prefira o SDKMAN! quando você precisar alternar versões por projeto.\nOpção 4: Homebrew (macOS) No macOS, se você já usa Homebrew:\nbrew install kotlin kotlin -version Simples e direto. A desvantagem em relação ao SDKMAN! é que o Homebrew gerencia apenas uma versão por vez. Se você precisa alternar entre versões, o SDKMAN! é a melhor escolha.\nOpção 5: Snap (Linux) No Linux, além do SDKMAN!, você pode instalar via Snap em distribuições que suportam esse gerenciador:\nsudo snap install kotlin --classic kotlin -version Para distribuições baseadas em Debian/Ubuntu que preferem usar o gerenciador de pacotes nativo, verifique se o Kotlin está disponível nos repositórios oficiais da sua distro.\nOpção 6: Sem instalar nada Se quiser apenas testar a linguagem antes de instalar qualquer coisa, use o Kotlin Playground direto no navegador:\n// Cole isso em play.kotlinlang.org e clique em Run fun main() { val linguagem = \u0026#34;Kotlin\u0026#34; val versao = \u0026#34;2.1\u0026#34; println(\u0026#34;$linguagem $versao rodando no navegador!\u0026#34;) println(\u0026#34;Nenhuma instalacao necessaria\u0026#34;) } Acesse play.kotlinlang.org e comece a codar imediatamente. O Playground suporta até importações de bibliotecas como kotlinx.coroutines, então dá pra testar bastante coisa sem instalar nada. Para aprender sobre coroutines e funções da linguagem, o Playground é um ótimo ponto de partida.\nPré-requisitos importantes Independente da opção escolhida, você precisa do JDK (Java Development Kit) instalado, já que Kotlin roda na JVM. (Curioso se precisa saber Java antes? Veja precisa saber Java para aprender Kotlin?.) O IntelliJ e o Android Studio geralmente cuidam disso automaticamente, mas se for usar a linha de comando:\n# Instalar JDK via SDKMAN! sdk install java 21-tem # Verificar java -version A versão recomendada do JDK é a 17 ou superior (LTS). O JDK 21 é a versão LTS mais recente e funciona muito bem com Kotlin. Evite usar versões muito antigas (abaixo do 11), pois algumas funcionalidades mais novas do Kotlin podem não funcionar corretamente.\nConfigurando o Gradle Para projetos mais estruturados, você vai precisar do Gradle como ferramenta de build. A boa notícia é que o IntelliJ e o Android Studio configuram o Gradle automaticamente ao criar um novo projeto. Se quiser configurar manualmente, o arquivo build.gradle.kts básico fica assim:\nplugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.1.0\u0026#34; application } repositories { mavenCentral() } dependencies { testImplementation(kotlin(\u0026#34;test\u0026#34;)) } application { mainClass.set(\u0026#34;MainKt\u0026#34;) } Temos um tutorial completo de Gradle com Kotlin que cobre tudo isso em detalhes.\nVerificação rápida da instalação Depois de instalar, rode estes comandos:\njava -version kotlin -version kotlinc -version Crie também um arquivo Main.kt:\nfun main() { println(\u0026#34;Kotlin instalado com sucesso\u0026#34;) } E execute:\nkotlinc Main.kt -include-runtime -d app.jar java -jar app.jar Se isso imprimir Kotlin instalado com sucesso, a instalação básica está funcionando. Para um primeiro projeto real, siga para primeiro programa em Kotlin ou Kotlin com Gradle.\nDicas de solução de problemas Às vezes a instalação não sai de primeira. Aqui vão alguns problemas comuns e como resolver:\n\u0026ldquo;kotlin: command not found\u0026rdquo; \u0026ndash; Isso acontece quando o Kotlin não está no PATH do sistema. Se usou SDKMAN!, execute source \u0026quot;$HOME/.sdkman/bin/sdkman-init.sh\u0026quot; ou reinicie o terminal. No macOS com Homebrew, verifique se /opt/homebrew/bin está no seu PATH. No Windows, prefira rodar pelo IntelliJ/Gradle antes de tentar instalar kotlinc globalmente.\n\u0026ldquo;Error: JAVA_HOME is not set\u0026rdquo; \u0026ndash; O Kotlin precisa do JDK pra funcionar. Instale o JDK conforme descrito acima e configure a variável de ambiente JAVA_HOME apontando para o diretório de instalação. Em projetos Gradle, confirme também com ./gradlew -version.\nVersão do Kotlin incompatível com o projeto \u0026ndash; Se ao abrir um projeto você vê erros de compatibilidade, verifique a versão do Kotlin configurada no build.gradle.kts e certifique-se de que o JDK instalado é compatível. O IntelliJ geralmente sugere a correção automaticamente.\nIntelliJ lento ou travando \u0026ndash; Aumente a memória alocada para o IDE em Help \u0026gt; Change Memory Settings. Para projetos Kotlin, 2 GB de heap é um bom ponto de partida.\nE agora? Com o Kotlin instalado, o próximo passo é criar seu primeiro projeto. Recomendo começar com algo simples: uma calculadora, uma lista de tarefas ou qualquer coisa que te motive a escrever código. O importante é praticar!\nSe quiser um caminho estruturado, siga esta ordem:\nPrimeiro programa em Kotlin \u0026ndash; o famoso \u0026ldquo;Olá, mundo\u0026rdquo; e seus primeiros passos Variáveis e tipos \u0026ndash; entenda val, var e o sistema de tipos Estruturas condicionais \u0026ndash; if, when e expressões Funções em Kotlin \u0026ndash; como criar e usar funções Classes e objetos \u0026ndash; programação orientada a objetos Aqui no Kotlin Brasil você encontra vários tutoriais e o guia completo de Kotlin pra te acompanhar nessa jornada. Se quiser um plano de estudos completo depois de instalar, veja como aprender Kotlin em 2026.\n","permalink":"https://kotlin.dev.br/perguntas/como-instalar-kotlin/","summary":"\u003ch2 id=\"como-instalar-kotlin\"\u003eComo instalar Kotlin?\u003c/h2\u003e\n\u003cdiv data-growth-refresh=\"2026-06-27-install-kotlin-ctr-ptbr\"\u003e\n\u003cp\u003e\u003cstrong\u003eResposta rápida:\u003c/strong\u003e a forma mais simples de instalar Kotlin é usar o \u003cstrong\u003eIntelliJ IDEA Community Edition\u003c/strong\u003e ou o \u003cstrong\u003eAndroid Studio\u003c/strong\u003e, porque já vêm com suporte completo a Kotlin embutido, sem configurar nada. Para quem prefere o terminal: no macOS e no Linux, instale o \u003cstrong\u003eSDKMAN!\u003c/strong\u003e e rode \u003ccode\u003esdk install kotlin\u003c/code\u003e; no macOS com Homebrew, \u003ccode\u003ebrew install kotlin\u003c/code\u003e também funciona; no Windows, o ideal é começar pelo IntelliJ/Android Studio (ou usar WSL com SDKMAN!). Em qualquer caso você também precisa de um \u003cstrong\u003eJDK\u003c/strong\u003e, de preferência o JDK 17 ou JDK 21.\u003c/p\u003e","title":"Como Instalar Kotlin em 2026: Passo a Passo (Windows, Mac e Linux) | Kotlin Brasil"},{"content":"O que é Kotlin Multiplatform? Imagine escrever a lógica do seu aplicativo uma única vez e usar esse mesmo código no Android, no iOS, na web e no desktop. Parece bom demais pra ser verdade? Pois é exatamente isso que o Kotlin Multiplatform (KMP) propõe.\nComo funciona? Diferente de frameworks como Flutter ou React Native, que tentam unificar tudo (incluindo a interface), o KMP tem uma abordagem diferente: ele permite compartilhar a lógica de negócio entre plataformas, enquanto a UI continua nativa em cada uma.\nNa prática, isso significa:\nA camada de rede, regras de negócio, válidações e modelos de dados são escritos uma vez em Kotlin A interface do Android usa Jetpack Compose nativo A interface do iOS usa SwiftUI nativo Cada plataforma mantém a experiência que o usuário espera Arquitetura de um projeto KMP Pra entender melhor, vamos olhar como um projeto KMP é organizado na prática. A estrutura segue o conceito de source sets, que são conjuntos de código destinados a alvos específicos:\ncommonMain: o código compartilhado entre todas as plataformas. Aqui ficam interfaces, data classes, regras de negócio e tudo que não depende de API nativa androidMain: implementações específicas para Android iosMain: implementações específicas para iOS desktopMain: implementações para JVM desktop (quando aplicável) O mecanismo de expect/actual é o que conecta tudo. Você declara uma função ou classe com expect no código compartilhado e fornece a implementação com actual em cada plataforma:\n// commonMain - declaracao expect expect fun obterPlataforma(): String // androidMain - implementacao actual actual fun obterPlataforma(): String = \u0026#34;Android ${android.os.Build.VERSION.SDK_INT}\u0026#34; // iosMain - implementacao actual actual fun obterPlataforma(): String = \u0026#34;iOS ${UIDevice.currentDevice.systemVersion}\u0026#34; Essa abordagem garante que o código compartilhado permanece independente de plataforma, enquanto cada alvo pode acessar suas APIs nativas quando necessário.\nExemplo de código compartilhado // Codigo compartilhado (commonMain) // Roda tanto no Android quanto no iOS class CalculadoraFrete { fun calcular(distanciaKm: Double, pesoKg: Double): Double { val taxaBase = 5.0 val taxaPorKm = 0.50 val taxaPorKg = 0.30 return taxaBase + (distanciaKm * taxaPorKm) + (pesoKg * taxaPorKg) } fun formatarPreco(valor: Double): String { return \u0026#34;R$ ${\u0026#34;%.2f\u0026#34;.format(valor)}\u0026#34; } } // Pode ser usado tanto no Android quanto no iOS! val calculadora = CalculadoraFrete() val frete = calculadora.calcular(distanciaKm = 150.0, pesoKg = 3.5) println(calculadora.formatarPreco(frete)) // R$ 81.05 O que dá pra compartilhar? Modelos de dados: classes, enums, data classes Lógica de negócio: cálculos, válidações, regras Camada de rede: chamadas de API com Ktor Persistência local: banco de dados com SQLDelight Gerenciamento de estado: ViewModels compartilhados E o Compose Multiplatform? Além de compartilhar a lógica, a JetBrains também desenvolveu o Compose Multiplatform, que leva a API do Jetpack Compose para iOS, desktop e web. Com isso, é possível compartilhar até a interface entre plataformas, se esse for o objetivo do seu projeto.\nO Compose Multiplatform utiliza os mesmos conceitos de Composables, State e Modifiers que você já conhece do Jetpack Compose. Se você domina o básico de Compose, a transição é bem suave.\nCasos de uso reais Empresas grandes já adotaram KMP em produção:\nNetflix: compartilha lógica entre apps mobile Philips: usa KMP em seus produtos de saúde Cash App: um dos primeiros cases de sucesso Forbes, VMware e muitas outras Além das grandes empresas, startups brasileiras também têm adotado KMP para acelerar o time-to-market. Com uma única equipe escrevendo a lógica de negócio, o custo de desenvolvimento cai drasticamente. Em vez de manter dois times separados (um para Android, outro para iOS), uma equipe menor consegue entregar para ambas as plataformas com qualidade.\nUm cenário comum é o de fintechs que precisam garantir que os cálculos financeiros sejam idênticos em todas as plataformas. Com KMP, a lógica de cálculo de juros, taxas e conversões é escrita uma única vez e testada uma única vez, eliminando o risco de divergências entre apps.\nKMP vs Flutter vs React Native Aspecto KMP Flutter React Native UI Nativa por padrão Própria (Skia) Ponte nativa Linguagem Kotlin Dart JavaScript/TS Compartilhamento Lógica (ou tudo com Compose) Tudo Tudo Performance Nativa Quase nativa Variável O ecossistema e o futuro do KMP O ecossistema de bibliotecas para KMP cresceu muito nos últimos anos. Ferramentas como Ktor (cliente HTTP), SQLDelight (banco de dados), Koin (injeção de dependência) e kotlinx.serialization (serialização) já são estáveis e amplamente utilizadas.\nO suporte do Gradle para projetos multiplataforma também amadureceu, tornando a configuração mais simples. E com o Google declarando KMP como abordagem recomendada para compartilhamento de lógica em apps Android, a tendência é que o ecossistema cresça ainda mais rápido.\nPara quem quer começar, o tutorial de Kotlin Multiplatform do nosso site é um ótimo ponto de partida. E se você já trabalha com Android, o guia de KMP mobile mostra como integrar código compartilhado em um projeto existente.\nVale a pena investir em KMP? O KMP alcançou estabilidade em 2023 e desde então o ecossistema amadureceu bastante. Se você já programa em Kotlin, entrar no mundo multiplataforma fica muito mais natural. A tendência é que cada vez mais empresas adotem essa tecnologia, e sair na frente nesse conhecimento é um baita diferencial competitivo.\nPara aprofundar seus conhecimentos, vale estudar os conceitos de coroutines e Flow, que são a base da programação assíncrona em projetos KMP. O guia completo de coroutines cobre tudo que você precisa saber.\n","permalink":"https://kotlin.dev.br/perguntas/kotlin-multiplatform-o-que-e/","summary":"\u003ch2 id=\"o-que-é-kotlin-multiplatform\"\u003eO que é Kotlin Multiplatform?\u003c/h2\u003e\n\u003cp\u003eImagine escrever a lógica do seu aplicativo \u003cstrong\u003euma única vez\u003c/strong\u003e e usar esse mesmo código no Android, no iOS, na web e no desktop. Parece bom demais pra ser verdade? Pois é exatamente isso que o \u003cstrong\u003eKotlin Multiplatform (KMP)\u003c/strong\u003e propõe.\u003c/p\u003e\n\u003ch3 id=\"como-funciona\"\u003eComo funciona?\u003c/h3\u003e\n\u003cp\u003eDiferente de frameworks como Flutter ou React Native, que tentam unificar \u003cstrong\u003etudo\u003c/strong\u003e (incluindo a interface), o KMP tem uma abordagem diferente: ele permite compartilhar a \u003cstrong\u003elógica de negócio\u003c/strong\u003e entre plataformas, enquanto a UI continua nativa em cada uma.\u003c/p\u003e","title":"O que É Kotlin Multiplatform? | Kotlin Brasil"},{"content":"Quanto ganha um desenvolvedor Kotlin? Vamos falar de grana? Afinal, todo mundo quer saber se o investimento de tempo pra aprender uma linguagem vai dar retorno financeiro. E quando o assunto é Kotlin, as notícias são bem animadoras.\nFaixas salariais no Brasil (2026) Os valores variam bastante dependendo da região, do porte da empresa e do modelo de trabalho (presencial, híbrido ou remoto). Mas pra dar uma noção geral:\nNível Faixa salarial (CLT) Júnior R$ 3.500 a R$ 6.500 Pleno R$ 7.000 a R$ 13.000 Sênior R$ 13.000 a R$ 22.000 Especialista/Staff R$ 20.000 a R$ 30.000+ Esses valores consideram posições focadas em Android com Kotlin ou backend com Kotlin, que são as áreas com mais demanda. Em capitais como São Paulo, Campinas, Florianópolis e Belo Horizonte, os salários tendem a ser mais altos.\nPara quem trabalha com Jetpack Compose ou Kotlin Multiplatform, os valores podem ser ainda maiores por conta da escassez de profissionais especializados nessas tecnologias.\nTrabalho remoto para o exterior É aqui que a coisa fica interessante de verdade. Desenvolvedores brasileiros que trabalham remotamente para empresas estrangeiras podem alcançar valores significativamente maiores:\nNível Faixa mensal (USD) Pleno US$ 4.000 a US$ 7.000 Sênior US$ 7.000 a US$ 12.000 Staff/Principal US$ 12.000 a US$ 18.000+ Convertendo pro real, as cifras são bem atrativas. Mas lembre-se que trabalhar como PJ para o exterior envolve custos com contador, impostos e câmbio.\nSalários internacionais por região Para quem quer entender o cenário global, os salários anuais de desenvolvedores Kotlin variam bastante conforme o país:\nRegião Faixa anual (USD) Estados Unidos US$ 100.000 a US$ 180.000 Europa Ocidental US$ 60.000 a US$ 120.000 Europa Oriental US$ 35.000 a US$ 70.000 América Latina (remoto) US$ 48.000 a US$ 120.000 Esses números ajudam a entender por que tantos devs brasileiros buscam posições remotas internacionais. O diferencial salarial é expressivo e a qualidade dos profissionais brasileiros é reconhecida lá fora.\nO que influencia o salário? Não é só saber Kotlin que define quanto você ganha. Outros fatores pesam bastante:\n// Fatores que impactam seu salario como dev Kotlin val fatoresSalariais = mapOf( \u0026#34;Dominio da linguagem\u0026#34; to \u0026#34;Fundamentos solidos + recursos avancados\u0026#34;, \u0026#34;Especializacao\u0026#34; to \u0026#34;Android, Backend, KMP\u0026#34;, \u0026#34;Ingles\u0026#34; to \u0026#34;Abre portas para vagas internacionais\u0026#34;, \u0026#34;Soft skills\u0026#34; to \u0026#34;Comunicacao, trabalho em equipe, lideranca\u0026#34;, \u0026#34;Portfolio\u0026#34; to \u0026#34;Projetos pessoais e contribuicoes open source\u0026#34;, \u0026#34;Certificacoes\u0026#34; to \u0026#34;Google Associate Android Developer, etc.\u0026#34; ) fatoresSalariais.forEach { (fator, detalhe) -\u0026gt; println(\u0026#34;$fator: $detalhe\u0026#34;) } Comparando com outras linguagens Kotlin paga, em média, valores comparáveis ou superiores a Java no mercado mobile. No backend, os salários ficam na mesma faixa de outras linguagens JVM. O diferencial é que a demanda por profissionais Kotlin tem crescido mais rápido que a oferta, o que pressiona os salários pra cima.\nQuem domina coroutines e Flow para programação assíncrona, por exemplo, se destaca bastante no mercado. Essas habilidades são valorizadas tanto em projetos Android quanto em backend com Ktor ou Spring Boot.\nDicas de negociação salarial Saber seu valor de mercado é fundamental na hora de negociar. Algumas estratégias que fazem diferença:\nPesquise antes: consulte plataformas como Glassdoor, Levels.fyi e pesquisas salariais de comunidades Kotlin para ter dados concretos em mãos Destaque especializações: se você domina Kotlin Multiplatform ou Clean Architecture, deixe isso claro \u0026ndash; são diferenciais que justificam salários mais altos Não aceite a primeira oferta: a maioria das empresas tem margem de negociação, especialmente para profissionais com habilidades em alta demanda Considere o pacote completo: além do salário base, avalie benefícios como PLR, stock options, plano de saúde, e flexibilidade de horário Mantenha um portfólio atualizado: contribuições open source e projetos pessoais demonstram competência de forma concreta Como crescer na carreira Kotlin O caminho de crescimento típico de um dev Kotlin passa por etapas bem definidas. No início, o foco deve ser nos fundamentos da linguagem \u0026ndash; variáveis, funções, classes e o sistema de null safety.\nCom o tempo, você pode se especializar em áreas que pagam mais:\nAndroid avançado: dominando Jetpack Compose, MVVM e testes Backend: construindo APIs com Ktor ou Spring Boot Multiplataforma: trabalhando com KMP para compartilhar código entre plataformas Liderança técnica: evoluindo para tech lead ou staff engineer, onde o salário sobe consideravelmente Como aumentar seu valor no mercado Domine pelo menos um framework (Jetpack Compose, Ktor ou Spring Boot) Invista no inglês, isso pode facilmente dobrar seu salário Contribua com projetos open source Participe de comunidades e eventos Mantenha-se atualizado com as novidades da linguagem O mercado pra devs Kotlin está aquecido e a tendência é continuar assim. É uma aposta segura pra quem quer crescer na carreira e ter boas condições financeiras.\n","permalink":"https://kotlin.dev.br/perguntas/salario-desenvolvedor-kotlin/","summary":"\u003ch2 id=\"quanto-ganha-um-desenvolvedor-kotlin\"\u003eQuanto ganha um desenvolvedor Kotlin?\u003c/h2\u003e\n\u003cp\u003eVamos falar de grana? Afinal, todo mundo quer saber se o investimento de tempo pra aprender uma linguagem vai dar retorno financeiro. E quando o assunto é Kotlin, as notícias são bem animadoras.\u003c/p\u003e\n\u003ch3 id=\"faixas-salariais-no-brasil-2026\"\u003eFaixas salariais no Brasil (2026)\u003c/h3\u003e\n\u003cp\u003eOs valores variam bastante dependendo da região, do porte da empresa e do modelo de trabalho (presencial, híbrido ou remoto). Mas pra dar uma noção geral:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eNível\u003c/th\u003e\n          \u003cth\u003eFaixa salarial (CLT)\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eJúnior\u003c/td\u003e\n          \u003ctd\u003eR$ 3.500 a R$ 6.500\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePleno\u003c/td\u003e\n          \u003ctd\u003eR$ 7.000 a R$ 13.000\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSênior\u003c/td\u003e\n          \u003ctd\u003eR$ 13.000 a R$ 22.000\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eEspecialista/Staff\u003c/td\u003e\n          \u003ctd\u003eR$ 20.000 a R$ 30.000+\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eEsses valores consideram posições focadas em \u003cstrong\u003eAndroid com Kotlin\u003c/strong\u003e ou \u003cstrong\u003ebackend com Kotlin\u003c/strong\u003e, que são as áreas com mais demanda. Em capitais como São Paulo, Campinas, Florianópolis e Belo Horizonte, os salários tendem a ser mais altos.\u003c/p\u003e","title":"Quanto Ganha um Desenvolvedor Kotlin? | Kotlin Brasil"},{"content":"Kotlin serve para backend? Serve e serve muito bem! Se você acha que Kotlin é só pra Android, está na hora de rever esse conceito. A linguagem vem conquistando cada vez mais espaço no desenvolvimento do lado do servidor, e com razão.\nPor que usar Kotlin no backend? Kotlin roda na JVM, então herda toda a robustez e o ecossistema maduro do Java. Mas vai além, oferecendo:\nCódigo mais enxuto: menos boilerplate significa mais produtividade Null safety: adeus NullPointerException em produção às 3 da manhã Coroutines: programação assíncrona eficiente e elegante Interoperabilidade com Java: use qualquer biblioteca Java existente Se você quer entender melhor o que são coroutines, temos um glossário completo sobre o tema. E para quem quer se aprofundar no conceito de null safety, vale a leitura também.\nOs frameworks mais populares Ktor Criado pela JetBrains, é um framework leve e assíncrono feito sob medida pra Kotlin. Ideal pra microsserviços e APIs:\nimport io.ktor.server.application.* import io.ktor.server.engine.* import io.ktor.server.netty.* import io.ktor.server.response.* import io.ktor.server.routing.* fun main() { embeddedServer(Netty, port = 8080) { routing { get(\u0026#34;/\u0026#34;) { call.respondText(\u0026#34;Fala, dev! A API tá no ar!\u0026#34;) } get(\u0026#34;/produtos\u0026#34;) { val produtos = listOf( mapOf(\u0026#34;id\u0026#34; to 1, \u0026#34;nome\u0026#34; to \u0026#34;Notebook\u0026#34;, \u0026#34;preco\u0026#34; to 3500.0), mapOf(\u0026#34;id\u0026#34; to 2, \u0026#34;nome\u0026#34; to \u0026#34;Mouse\u0026#34;, \u0026#34;preco\u0026#34; to 89.90) ) call.respond(produtos) } } }.start(wait = true) } Ktor brilha especialmente quando você quer ter controle total sobre o que está incluído no projeto. Diferente de frameworks opinados, ele funciona como um conjunto de plugins que você adiciona conforme a necessidade: autenticação, serialização, CORS, WebSockets. Se o seu cenário é construir microsserviços enxutos ou APIs de alta performance, Ktor é uma escolha excelente. Temos um guia completo de Ktor para backend e também um tutorial prático de Ktor para quem quer começar.\nSpring Boot O framework mais usado no mundo corporativo tem suporte oficial a Kotlin desde 2017. Se você já conhece Spring em Java, a transição é suave:\n@RestController class ProdutoController(private val repository: ProdutoRepository) { @GetMapping(\u0026#34;/produtos\u0026#34;) fun listarTodos(): List\u0026lt;Produto\u0026gt; = repository.findAll() @PostMapping(\u0026#34;/produtos\u0026#34;) fun criar(@RequestBody produto: Produto): Produto = repository.save(produto) } Spring Boot é a escolha natural para projetos corporativos de grande porte. Ele traz um ecossistema gigante com soluções para segurança (Spring Security), mensageria (Spring AMQP), batch processing e muito mais. Se você quer se aprofundar, confira nosso guia de Spring Boot com Kotlin e o tutorial de Spring Boot.\nComparando Ktor e Spring Boot Aspecto Ktor Spring Boot Tamanho do projeto Leve, modular Robusto, muitas dependências Curva de aprendizado Mais simples para quem conhece Kotlin Mais simples para quem já conhece Spring Coroutines Suporte nativo Suporte via WebFlux/coroutines Ecossistema Em crescimento Maduro e vasto Ideal para Microsserviços, APIs rápidas Aplicações enterprise, monolitos Quem usa Kotlin no backend? Empresas de peso já adotaram Kotlin no servidor:\nAmazon usa Kotlin em vários serviços internos Netflix migrou partes do backend pra Kotlin Mercado Livre tem times utilizando Kotlin no backend Nubank (que é muito forte em Clojure) também tem frentes com Kotlin No Brasil, startups e fintechs estão puxando essa tendência, mas empresas maiores também estão entrando nessa. Bancos digitais, plataformas de e-commerce e empresas de logística têm adotado Kotlin para novos serviços, especialmente quando precisam de alta performance e código mais legível.\nBanco de dados e ORM Pra trabalhar com banco de dados em Kotlin, as opções não faltam:\nExposed: ORM feito pela JetBrains, leve e idiomático Spring Data JPA: funciona perfeitamente com Kotlin jOOQ: geração de código type-safe pra consultas SQL Aqui vai um exemplo prático com Exposed, mostrando como definir uma tabela e fazer uma consulta:\nobject Produtos : Table() { val id = integer(\u0026#34;id\u0026#34;).autoIncrement() val nome = varchar(\u0026#34;nome\u0026#34;, 255) val preco = double(\u0026#34;preco\u0026#34;) override val primaryKey = PrimaryKey(id) } fun listarProdutosBaratos(): List\u0026lt;String\u0026gt; { return transaction { Produtos.select { Produtos.preco less 100.0 } .map { it[Produtos.nome] } } } Para entender melhor como classes e collections funcionam em Kotlin (conceitos fundamentais para trabalhar com ORMs), vale consultar nosso glossário.\nDeploy e infraestrutura Uma vantagem enorme do Kotlin no backend é que o deploy funciona exatamente como qualquer aplicação JVM. Você pode:\nGerar um JAR executável e rodar em qualquer servidor com Java instalado Empacotar com Docker usando imagens baseadas em OpenJDK Fazer deploy em serviços de nuvem como AWS, GCP ou Azure sem nenhuma configuração especial Usar GraalVM para compilação nativa e tempo de startup ultrarrápido Se você quer aprender mais sobre containerização, temos um guia de Kotlin com Docker e um guia de CI/CD que cobrem esse fluxo completo. Para quem está interessado em arquitetura de microsserviços, o guia de microsserviços com Kotlin é leitura obrigatória.\nVale a pena migrar? Se você já tem um backend em Java, a migração pode ser feita gradualmente, arquivo por arquivo, graças à interoperabilidade. Não precisa reescrever tudo de uma vez. Muitos times começam escrevendo os novos módulos em Kotlin e vão convertendo o código antigo aos poucos.\nUma estratégia comum em empresas brasileiras é definir que todo código novo deve ser escrito em Kotlin, enquanto o código Java existente só é convertido quando precisa de manutenção significativa. Dessa forma, a migração acontece organicamente, sem interromper entregas.\nPara quem está pensando em dar esse passo, nosso guia completo de Kotlin cobre desde os fundamentos até tópicos avançados, e o artigo sobre Kotlin ou Java pode ajudar a convencer o time.\nO Kotlin no backend não é modinha: é uma tendência consolidada que traz ganhos reais de produtividade e qualidade de código. Se você está pensando em experimentar, o momento é agora.\n","permalink":"https://kotlin.dev.br/perguntas/kotlin-para-backend/","summary":"\u003ch2 id=\"kotlin-serve-para-backend\"\u003eKotlin serve para backend?\u003c/h2\u003e\n\u003cp\u003eServe e serve \u003cstrong\u003emuito bem\u003c/strong\u003e! Se você acha que Kotlin é só pra Android, está na hora de rever esse conceito. A linguagem vem conquistando cada vez mais espaço no desenvolvimento do lado do servidor, e com razão.\u003c/p\u003e\n\u003ch3 id=\"por-que-usar-kotlin-no-backend\"\u003ePor que usar Kotlin no backend?\u003c/h3\u003e\n\u003cp\u003eKotlin roda na JVM, então herda toda a robustez e o ecossistema maduro do Java. Mas vai além, oferecendo:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eCódigo mais enxuto\u003c/strong\u003e: menos boilerplate significa mais produtividade\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNull safety\u003c/strong\u003e: adeus \u003ccode\u003eNullPointerException\u003c/code\u003e em produção às 3 da manhã\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCoroutines\u003c/strong\u003e: programação assíncrona eficiente e elegante\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eInteroperabilidade com Java\u003c/strong\u003e: use qualquer biblioteca Java existente\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSe você quer entender melhor o que são \u003ca href=\"/glossario/coroutine/\"\u003ecoroutines\u003c/a\u003e, temos um glossário completo sobre o tema. E para quem quer se aprofundar no conceito de \u003ca href=\"/glossario/nullable/\"\u003enull safety\u003c/a\u003e, vale a leitura também.\u003c/p\u003e","title":"Kotlin Serve para Backend? | Kotlin Brasil"},{"content":"O que são coroutines em Kotlin? Se você já estudou um pouco de Kotlin, com certeza já ouviu falar em coroutines. Esse é um dos recursos mais poderosos da linguagem, mas também um dos que mais gera dúvida. Bora desmistificar?\nExplicando de forma simples Coroutines são uma forma de escrever código assíncrono de maneira sequencial e legível. Em vez de lidar com callbacks aninhados (o famoso \u0026ldquo;callback hell\u0026rdquo;) ou com APIs complicadas de threads, você escreve código que parece síncrono, mas que por baixo dos panos não bloqueia a thread principal.\nPense assim: imagine que você está num restaurante. Em vez de ficar parado esperando o prato ficar pronto (bloqueando), você faz o pedido e vai fazer outra coisa enquanto a cozinha trabalha. Quando o prato fica pronto, você volta pra comer. É isso que uma coroutine faz com seu código.\nUm exemplo prático import kotlinx.coroutines.* fun main() = runBlocking { println(\u0026#34;Começando o programa...\u0026#34;) // Lança duas coroutines que rodam \u0026#34;ao mesmo tempo\u0026#34; val pedido1 = async { buscarDados(\u0026#34;Usuários\u0026#34;, 2000) } val pedido2 = async { buscarDados(\u0026#34;Produtos\u0026#34;, 1500) } // Espera os dois resultados println(pedido1.await()) println(pedido2.await()) println(\u0026#34;Tudo pronto!\u0026#34;) } suspend fun buscarDados(tipo: String, tempoMs: Long): String { delay(tempoMs) // Simula uma operacao demorada (nao bloqueia a thread!) return \u0026#34;Dados de $tipo carregados com sucesso\u0026#34; } Nesse exemplo, as duas buscas acontecem simultaneamente, e o tempo total é determinado pela mais lenta (2 segundos), e não pela soma das duas (3,5 segundos). Isso faz uma diferença enorme em aplicações reais.\nConceitos fundamentais suspend fun: marca uma função que pode ser suspensa e retomada sem bloquear a thread. Confira o glossário de suspend para entender melhor. launch: inicia uma coroutine sem esperar o resultado (tipo \u0026ldquo;dispara e esquece\u0026rdquo;). Veja mais no glossário de launch. async/await: inicia uma coroutine e permite aguardar o resultado depois. Detalhes no glossário de async. runBlocking: cria um escopo de coroutine bloqueante, usado normalmente no main ou em testes delay: pausa a coroutine sem bloquear a thread (diferente de Thread.sleep) Coroutines vs. Threads: qual a diferença? Essa comparação ajuda muito a entender o valor das coroutines. Threads são gerenciadas pelo sistema operacional e consomem recursos significativos \u0026ndash; cada thread precisa de sua própria pilha de memória (geralmente cerca de 1 MB). Já coroutines são gerenciadas pelo runtime do Kotlin e são extremamente leves.\nPara ilustrar, veja a diferença na prática:\nimport kotlinx.coroutines.* // Com coroutines: roda 100.000 sem problemas fun main() = runBlocking { val tarefas = List(100_000) { launch { delay(1000) print(\u0026#34;.\u0026#34;) } } tarefas.forEach { it.join() } println(\u0026#34;\\nTodas as coroutines terminaram!\u0026#34;) } Tentar criar 100.000 threads tradicionais provavelmente causaria um OutOfMemoryError. Já com coroutines, isso roda de boas porque elas compartilham um pool pequeno de threads por baixo dos panos.\nOutra diferença importante: threads usam preemptive multitasking (o sistema operacional decide quando pausar), enquanto coroutines usam cooperative multitasking (a coroutine decide quando ceder o controle, nos pontos de suspensão). Isso torna o comportamento mais previsível.\nDispatchers: onde a coroutine executa Os dispatchers definem em qual thread ou pool de threads a coroutine vai rodar. Escolher o dispatcher correto é essencial:\nimport kotlinx.coroutines.* suspend fun exemploDispatchers() { // Para operacoes de CPU (processamento pesado) withContext(Dispatchers.Default) { // Calculos complexos, ordenacao, etc. } // Para operacoes de I/O (rede, banco de dados, arquivos) withContext(Dispatchers.IO) { // Chamadas de API, leitura de arquivos, queries no banco } // Para atualizar a UI (Android) withContext(Dispatchers.Main) { // Atualizar textos, mostrar dados na tela } } Usar Dispatchers.IO para chamadas de rede e Dispatchers.Default para processamento pesado evita que a thread principal fique bloqueada. No Android, isso é obrigatório para manter o app responsivo.\nQuando usar coroutines? Coroutines brilham em cenários como:\nChamadas de API: buscar dados de um servidor sem congelar a interface do app Acesso a banco de dados: consultas ao Room ou outros bancos locais Operações paralelas: quando você precisa fazer várias coisas ao mesmo tempo e combinar os resultados Tarefas em background: processamento de imagens, sincronização de dados, uploads Streams de dados: combinadas com Flow, permitem trabalhar com fluxos de dados reativos. Veja nosso tutorial de Kotlin Flow e o guia completo de coroutines. Structured Concurrency: coroutines organizadas Um conceito central em Kotlin é a concorrência estruturada. Toda coroutine precisa ser lançada dentro de um escopo (CoroutineScope), e esse escopo controla o ciclo de vida de todas as coroutines filhas. Se o escopo for cancelado, todas as coroutines dentro dele também são canceladas automaticamente.\nimport kotlinx.coroutines.* fun main() = runBlocking { val job = launch { launch { tarefaA() } launch { tarefaB() } // Se esse escopo for cancelado, tarefaA e tarefaB tambem sao } delay(500) job.cancel() // Cancela tudo de uma vez println(\u0026#34;Tarefas canceladas\u0026#34;) } suspend fun tarefaA() { repeat(10) { delay(200) println(\u0026#34;Tarefa A: passo $it\u0026#34;) } } suspend fun tarefaB() { repeat(10) { delay(300) println(\u0026#34;Tarefa B: passo $it\u0026#34;) } } Para entender melhor como escopos e jobs funcionam juntos, confira o tutorial avançado de coroutines.\nPor que coroutines são tão importantes? No desenvolvimento Android, a thread principal (UI thread) não pode ser bloqueada, senão o app trava. Coroutines resolvem isso de forma elegante, permitindo que operações pesadas como chamadas de API e acesso a banco de dados rodem sem congelar a interface. No Android, os escopos mais usados são viewModelScope e lifecycleScope, que se integram com o ViewModel e o ciclo de vida dos componentes.\nNo backend, coroutines permitem que um servidor atenda milhares de requisições simultâneas com muito menos recursos do que seria necessário usando threads tradicionais. Frameworks como Ktor foram construídos em cima de coroutines, e até o Spring Boot com Kotlin oferece suporte nativo.\nO principal cuidado Coroutines são leves, mas não são mágicas. É importante entender os escopos e o ciclo de vida de cada coroutine pra evitar vazamentos de memória e comportamentos inesperados. No Android, por exemplo, use viewModelScope ou lifecycleScope em vez de criar escopos soltos.\nOutro cuidado comum: nunca use runBlocking dentro de uma coroutine. Ele bloqueia a thread atual e pode causar deadlocks. Reserve o runBlocking para o main() e para testes unitários.\nDominar coroutines leva um tempinho, mas é um investimento que vale muito a pena. É um daqueles conhecimentos que transformam a forma como você programa. Para ir mais fundo, comece pelo tutorial básico de coroutines e depois avance para o guia completo.\n","permalink":"https://kotlin.dev.br/perguntas/o-que-sao-coroutines/","summary":"\u003ch2 id=\"o-que-são-coroutines-em-kotlin\"\u003eO que são coroutines em Kotlin?\u003c/h2\u003e\n\u003cp\u003eSe você já estudou um pouco de Kotlin, com certeza já ouviu falar em \u003cstrong\u003ecoroutines\u003c/strong\u003e. Esse é um dos recursos mais poderosos da linguagem, mas também um dos que mais gera dúvida. Bora desmistificar?\u003c/p\u003e\n\u003ch3 id=\"explicando-de-forma-simples\"\u003eExplicando de forma simples\u003c/h3\u003e\n\u003cp\u003eCoroutines são uma forma de escrever \u003cstrong\u003ecódigo assíncrono de maneira sequencial e legível\u003c/strong\u003e. Em vez de lidar com callbacks aninhados (o famoso \u0026ldquo;callback hell\u0026rdquo;) ou com APIs complicadas de threads, você escreve código que parece síncrono, mas que por baixo dos panos não bloqueia a thread principal.\u003c/p\u003e","title":"O que São Coroutines em Kotlin? | Kotlin Brasil"},{"content":"Qual a diferença entre val e var em Kotlin? Essa é uma das primeiras coisas que você aprende em Kotlin, e entender direitinho a diferença entre val e var vai te poupar muita dor de cabeça. Vamos lá!\nA explicação rápida val (de value): declara uma variável imutável. Depois que você atribui um valor, não pode mais mudar. var (de variable): declara uma variável mutável. Você pode alterar o valor quantas vezes quiser. Pense assim: val é como escrever a caneta, e var é como escrever a lápis.\nSe você quer se aprofundar nesses conceitos, temos páginas dedicadas no glossário para val e var, além de um tutorial completo sobre variáveis e tipos em Kotlin.\nNa prática fun main() { // val - imutável: uma vez atribuído, não muda val nome = \u0026#34;Karina\u0026#34; // nome = \u0026#34;Ana\u0026#34; // ERRO! Não pode reatribuir um val // var - mutável: pode mudar à vontade var pontuacao = 0 println(\u0026#34;Pontuação inicial: $pontuacao\u0026#34;) pontuacao = 10 println(\u0026#34;Pontuação atualizada: $pontuacao\u0026#34;) pontuacao += 5 println(\u0026#34;Pontuação final: $pontuacao\u0026#34;) } Se você tentar reatribuir um val, o compilador vai reclamar na hora com um erro bem claro. Isso é uma mão na roda pra evitar bugs.\nQuando usar cada um? A regra de ouro é: prefira sempre val. Use var somente quando realmente precisar alterar o valor depois.\nPor que? Variáveis imutáveis tornam o código mais previsível e seguro. Quando você sabe que um valor não vai mudar, fica muito mais fácil entender o que o código está fazendo.\nfun main() { // Boas práticas val cpf = \u0026#34;123.456.789-00\u0026#34; // CPF não muda, usa val val dataNascimento = \u0026#34;15/03/1995\u0026#34; // data de nascimento não muda, usa val var saldo = 1000.0 // saldo muda, usa var saldo -= 150.0 // compra no débito println(\u0026#34;Saldo atual: R$ $saldo\u0026#34;) } Cuidado: val não significa objeto imutável Um detalhe que pega muita gente: val impede a reatribuição, mas não impede a modificação interna do objeto. Veja:\nfun main() { val frutas = mutableListOf(\u0026#34;Banana\u0026#34;, \u0026#34;Maçã\u0026#34;, \u0026#34;Manga\u0026#34;) // Isso funciona! Estamos modificando a lista, não reatribuindo a variável frutas.add(\u0026#34;Abacaxi\u0026#34;) println(frutas) // [Banana, Maçã, Manga, Abacaxi] // Isso NÃO funciona! Estamos tentando reatribuir // frutas = mutableListOf(\u0026#34;Uva\u0026#34;) // ERRO! } Se quiser uma lista que não pode ser modificada de jeito nenhum, use listOf() em vez de mutableListOf(). Para entender melhor as diferenças entre coleções mutáveis e imutáveis, confira nosso conteúdo sobre collections e o tutorial de coleções em Kotlin.\nErros comuns de quem está começando Vamos ver alguns erros que aparecem com frequência e como evitá-los:\n1. Usar var quando val resolveria // Ruim: var desnecessário var mensagem = \u0026#34;Bem-vindo ao sistema\u0026#34; println(mensagem) // Bom: se não vai mudar, use val val mensagem = \u0026#34;Bem-vindo ao sistema\u0026#34; println(mensagem) O IntelliJ IDEA e o Android Studio inclusive exibem um aviso quando você declara um var que nunca é reatribuído, sugerindo trocar para val.\n2. Confundir imutabilidade da referência com imutabilidade do conteúdo fun main() { val numeros = mutableListOf(1, 2, 3) numeros.add(4) // Funciona: estamos alterando o conteúdo // numeros = mutableListOf(5) // ERRO: estamos tentando reatribuir a referência // Para imutabilidade total, combine val com coleção imutável val numerosFixos = listOf(1, 2, 3) // numerosFixos.add(4) // ERRO: listOf() não tem método add } 3. Esquecer que val funciona diferente em classes Dentro de uma classe, val define uma propriedade somente leitura, enquanto var define uma propriedade que pode ser alterada:\nclass ContaBancaria(val titular: String, var saldo: Double) { fun depositar(valor: Double) { saldo += valor // OK: saldo é var } // titular não pode ser alterado depois da criação } fun main() { val conta = ContaBancaria(\u0026#34;Maria\u0026#34;, 500.0) conta.depositar(200.0) println(\u0026#34;Saldo: ${conta.saldo}\u0026#34;) // 700.0 // conta.titular = \u0026#34;Joao\u0026#34; // ERRO! titular é val } val e var em funções Parâmetros de funções em Kotlin são sempre imutáveis (equivalentes a val). Você não pode reatribuir um parâmetro dentro do corpo da função:\nfun calcularDesconto(preco: Double, percentual: Double): Double { // preco = preco * 0.9 // ERRO! Parâmetros são imutáveis val precoComDesconto = preco * (1 - percentual / 100) return precoComDesconto } Essa decisão de design foi intencional. Ela evita efeitos colaterais confusos e torna o código mais previsível. Se você vem do Java, onde parâmetros podem ser reatribuídos, vai notar essa diferença logo de cara.\nval e var com delegação de propriedades Kotlin tem um recurso avançado chamado delegação de propriedades que funciona tanto com val quanto com var. O exemplo mais conhecido é o lazy, que só inicializa o valor quando ele é acessado pela primeira vez:\nval configuracao: Map\u0026lt;String, String\u0026gt; by lazy { println(\u0026#34;Carregando configuração...\u0026#34;) mapOf(\u0026#34;tema\u0026#34; to \u0026#34;escuro\u0026#34;, \u0026#34;idioma\u0026#34; to \u0026#34;pt-BR\u0026#34;) } fun main() { println(\u0026#34;Antes de acessar\u0026#34;) println(configuracao[\u0026#34;tema\u0026#34;]) // Só aqui o bloco lazy é executado } Para saber mais sobre esse recurso, veja nosso glossário sobre property delegate.\nResumindo Aspecto val var Reatribuição Não permite Permite Equivalente em Java final variável comum Quando usar Sempre que possível Quando precisar mudar o valor Parâmetros de função Comportamento padrão Não disponível Performance Pode ser otimizado pelo compilador Sem otimizações extras Adotar o hábito de usar val por padrão é uma das melhores práticas em Kotlin. Seu código fica mais limpo, mais seguro e mais fácil de manter. Na dúvida, comece com val e só troque pra var se o compilador reclamar que você está tentando alterar o valor.\nSe você quer continuar aprendendo sobre os fundamentos da linguagem, confira nosso guia completo de Kotlin e o tutorial sobre funções em Kotlin. Para entender o conceito mais amplo de imutabilidade e por que ele é tão importante na programação moderna, temos um artigo dedicado no glossário.\n","permalink":"https://kotlin.dev.br/perguntas/diferenca-val-var/","summary":"\u003ch2 id=\"qual-a-diferença-entre-val-e-var-em-kotlin\"\u003eQual a diferença entre val e var em Kotlin?\u003c/h2\u003e\n\u003cp\u003eEssa é uma das primeiras coisas que você aprende em Kotlin, e entender direitinho a diferença entre \u003ccode\u003eval\u003c/code\u003e e \u003ccode\u003evar\u003c/code\u003e vai te poupar muita dor de cabeça. Vamos lá!\u003c/p\u003e\n\u003ch3 id=\"a-explicação-rápida\"\u003eA explicação rápida\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003eval\u003c/code\u003e\u003c/strong\u003e (de \u003cem\u003evalue\u003c/em\u003e): declara uma variável \u003cstrong\u003eimutável\u003c/strong\u003e. Depois que você atribui um valor, não pode mais mudar.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003evar\u003c/code\u003e\u003c/strong\u003e (de \u003cem\u003evariable\u003c/em\u003e): declara uma variável \u003cstrong\u003emutável\u003c/strong\u003e. Você pode alterar o valor quantas vezes quiser.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003ePense assim: \u003ccode\u003eval\u003c/code\u003e é como escrever a caneta, e \u003ccode\u003evar\u003c/code\u003e é como escrever a lápis.\u003c/p\u003e","title":"Qual a Diferença entre val e var em Kotlin? | Kotlin Brasil"},{"content":"O ecossistema Kotlin continua evoluindo de forma impressionante, e 2026 trouxe algumas das atualizações mais significativas desde o lançamento da linguagem. Se você é desenvolvedor Kotlin ou está considerando adotar a linguagem, este é o momento ideal para entender o que mudou e como essas novidades podem impactar seus projetos. Neste artigo, vamos explorar em profundidade todas as principais novidades do Kotlin em 2026, desde melhorias no compilador até novos recursos da linguagem.\nO Novo Compilador K2: Estabilidade e Performance O compilador K2, que vinha sendo desenvolvido há alguns anos, finalmente atingiu maturidade completa em 2026. As melhorias são notáveis em diversos aspectos. A velocidade de compilação aumentou significativamente, com ganhos de até 2x em projetos grandes comparado ao compilador legado. Isso significa que aquele tempo de build que antes consumia minutos agora pode ser reduzido pela metade.\nAlém da velocidade, o K2 trouxe melhorias substanciais na inferência de tipos. O compilador agora consegue resolver cenários mais complexos de forma automática, reduzindo a necessidade de anotações explícitas de tipo. Isso torna o código mais limpo e legível sem sacrificar a segurança de tipos que é uma das marcas registradas do Kotlin.\n// Antes: necessario especificar tipo explicitamente em alguns cenarios val resultado: Map\u0026lt;String, List\u0026lt;Pair\u0026lt;Int, String\u0026gt;\u0026gt;\u0026gt; = buildMap { put(\u0026#34;dados\u0026#34;, listOf(Pair(1, \u0026#34;teste\u0026#34;))) } // Agora: inferência de tipos mais inteligente val resultado = buildMap { put(\u0026#34;dados\u0026#34;, listOf(1 to \u0026#34;teste\u0026#34;)) } O novo compilador também trouxe mensagens de erro muito mais claras e descritivas. Quando algo dá errado, o desenvolvedor agora recebe sugestões contextuais de como corrigir o problema, o que acelera bastante o ciclo de desenvolvimento. Se você ainda não migrou para o K2, confira nosso guia completo de migração para fazer a transição de forma segura.\nKotlin Multiplatform: Produção em Larga Escala O Kotlin Multiplatform (KMP) deixou de ser uma promessa e se consolidou como uma solução robusta para desenvolvimento multiplataforma em 2026. Grandes empresas como Netflix, Philips e Cash App já utilizam KMP em produção, compartilhando lógica de negócios entre Android, iOS, web e desktop.\nUma das grandes novidades de 2026 foi a introdução do suporte aprimorado a bibliotecas nativas em cada plataforma. Agora é possível criar expect/actual declarations de forma muito mais fluida, com melhor suporte do IDE e verificação de compatibilidade em tempo de compilação.\n// Código compartilhado entre plataformas expect class PlatformLogger() { fun log(message: String, level: LogLevel) fun getDeviceInfo(): DeviceInfo } // Implementação Android actual class PlatformLogger { actual fun log(message: String, level: LogLevel) { Log.d(\u0026#34;KotlinApp\u0026#34;, \u0026#34;[$level] $message\u0026#34;) } actual fun getDeviceInfo(): DeviceInfo { return DeviceInfo(Build.MODEL, Build.VERSION.SDK_INT.toString()) } } // Implementação iOS actual class PlatformLogger { actual fun log(message: String, level: LogLevel) { NSLog(\u0026#34;[$level] $message\u0026#34;) } actual fun getDeviceInfo(): DeviceInfo { let device = UIDevice.current return DeviceInfo(device.model, device.systemVersion) } } O ecossistema de bibliotecas multiplataforma também cresceu enormemente. Bibliotecas populares como Ktor, SQLDelight, Koin e muitas outras agora oferecem suporte completo a todas as plataformas-alvo do KMP. Para aprender mais sobre KMP, acesse nosso tutorial de Kotlin Multiplatform.\nContext Receivers e Context Parameters Uma das funcionalidades mais aguardadas pela comunidade Kotlin finalmente ganhou estabilidade em 2026: os context parameters (evolução dos context receivers). Esse recurso permite definir dependências implícitas de contexto para funções e classes, eliminando a necessidade de passar parâmetros repetitivos em cadeias de chamadas.\ncontext(logger: Logger, config: AppConfig) fun processarPedido(pedido: Pedido): Resultado { logger.info(\u0026#34;Processando pedido ${pedido.id}\u0026#34;) val taxaEntrega = if (config.freteGratis \u0026amp;\u0026amp; pedido.valor \u0026gt; config.valorMinimoFreteGratis) { 0.0 } else { calcularFrete(pedido.endereco) } return Resultado.Sucesso(pedido.copy(taxaEntrega = taxaEntrega)) } context(logger: Logger, config: AppConfig) fun calcularFrete(endereco: Endereco): Double { logger.debug(\u0026#34;Calculando frete para ${endereco.cep}\u0026#34;) // Lógica de cálculo de frete return config.taxaBase * endereco.distanciaKm } Esse recurso é especialmente útil em arquiteturas limpas, onde dependências como loggers, configurações e repositórios precisam estar disponíveis em múltiplas camadas sem poluir assinaturas de funções. Entenda melhor esse conceito no nosso glossário de termos Kotlin.\nMelhorias em Coroutines e Flow O sistema de coroutines do Kotlin recebeu atualizações importantes em 2026. A principal novidade é o suporte a structured concurrency aprimorado, com novas APIs qué fácilitam o gerenciamento de ciclo de vida de coroutines em cenários complexos.\n// Novo operador de merge para Flows val fluxoCombinado = merge( fluxoUsuarios.map { \u0026#34;Usuário: ${it.nome}\u0026#34; }, fluxoNotificacoes.map { \u0026#34;Notificação: ${it.titulo}\u0026#34; }, fluxoAlertas.map { \u0026#34;Alerta: ${it.mensagem}\u0026#34; } ) // Novo SharedFlow com replay configurável e política de overflow val eventBus = MutableSharedFlow\u0026lt;Evento\u0026gt;( replay = 10, extraBufferCapacity = 50, onBufferOverflow = BufferOverflow.DROP_OLDEST ) // Melhor suporte a timeout e retry val dados = retryWithBackoff( maxRetries = 3, initialDelay = 1.seconds, maxDelay = 30.seconds ) { apiService.buscarDados() } Outra melhoria significativa é o melhor suporte a debugging de coroutines. O IntelliJ IDEA agora mostra o stack trace completo de coroutines, incluindo o ponto de suspensão e a hierarquia completa do CoroutineScope. Isso facilita enormemente a identificação de problemas em código assíncrono.\nCompose Multiplatform 2.0 O Compose Multiplatform atingiu a versão 2.0 em 2026, trazendo paridade quase completa entre todas as plataformas suportadas. Agora é possível criar interfaces nativas para Android, iOS, desktop (Windows, macOS, Linux) e web usando uma única base de código Compose.\nAs principais melhorias incluem performance significativamente melhor no iOS, com renderização nativa usando Metal. Componentes adaptativos que se ajustam automaticamente ao design system de cada plataforma (Material Design no Android, Cupertino no iOS) também foram introduzidos. O hot reload funciona agora em todas as plataformas, não apenas no Android.\n@Composable fun TelaInicial(viewModel: InicialViewModel) { AdaptiveScaffold( topBar = { AdaptiveTopBar(titulo = \u0026#34;Meu App Kotlin\u0026#34;) } ) { padding -\u0026gt; LazyColumn(modifier = Modifier.padding(padding)) { items(viewModel.itens) { item -\u0026gt; CartaoItem( titulo = item.titulo, descricao = item.descricao, onClick = { viewModel.selecionarItem(item) } ) } } } } Kotlin para Backend: Novas Integrações No mundo backend, o Kotlin consolidou sua posição como uma alternativa moderna ao Java. Em 2026, frameworks como Ktor e Spring Boot expandiram significativamente seu suporte ao Kotlin. O Spring Boot 4, lançado recentemente, traz suporte nativo a coroutines em todos os seus módulos, eliminando a necessidade de adaptadores.\nO Ktor, framework web nativo do Kotlin, lançou a versão 3.0 com suporte a HTTP/3, WebTransport e melhor integração com Kotlin Multiplatform. Agora é possível compartilhar modelos de dados e lógica de válidação entre cliente e servidor de forma transparente.\nPara quem trabalha com microserviços, o ecossistema Kotlin agora oferece soluções completas para observabilidade, incluindo integração nativa com OpenTelemetry, métricas estruturadas e tracing distribuído. Veja nossos tutoriais de backend com Kotlin para começar.\nConclusão O Kotlin em 2026 está mais maduro, rápido e versátil do que nunca. Com o compilador K2 estável, Kotlin Multiplatform em produção, Compose Multiplatform 2.0 e as diversas melhorias na linguagem, não há momento melhor para investir no ecossistema Kotlin.\nSe você está começando agora, explore nossos tutoriais de Kotlin para dar os primeiros passos. Se já é um desenvolvedor experiente, confira nossos guias avançados para aproveitar ao máximo as novidades de 2026. E não se esqueça de consultar o glossário Kotlin sempre que encontrar um termo desconhecido.\nO futuro do desenvolvimento de software passa pelo Kotlin, e a comunidade brasileira está mais ativa do que nunca. Outras linguagens que também trouxeram novidades empolgantes em 2026 incluem Go, Rust e Python. Participe, contribua e faça parte dessa revolução!\n","permalink":"https://kotlin.dev.br/blog/kotlin-2026-novidades/","summary":"\u003cp\u003eO ecossistema Kotlin continua evoluindo de forma impressionante, e 2026 trouxe algumas das atualizações mais significativas desde o lançamento da linguagem. Se você é desenvolvedor Kotlin ou está considerando adotar a linguagem, este é o momento ideal para entender o que mudou e como essas novidades podem impactar seus projetos. Neste artigo, vamos explorar em profundidade todas as principais novidades do Kotlin em 2026, desde melhorias no compilador até novos recursos da linguagem.\u003c/p\u003e","title":"Novidades do Kotlin em 2026 — 2026 | Kotlin Brasil"},{"content":"Kotlin é difícil de aprender? Vamos direto ao ponto: não, Kotlin não é uma linguagem difícil de aprender. Pelo contrário, ela foi projetada desde o início para ser clara, concisa e agradável de usar. Mas isso não quer dizer que não existam desafios pelo caminho.\nPor que Kotlin é considerada acessível? A sintaxe do Kotlin foi pensada pra reduzir a \u0026ldquo;burocracia\u0026rdquo; que existe em outras linguagens. Veja como é simples declarar variáveis e criar funções:\n// Variaveis com inferencia de tipo val nome = \u0026#34;Maria\u0026#34; // imutavel (nao muda) var idade = 25 // mutavel (pode mudar) // Funcao simples e direta fun saudacao(nome: String): String { return \u0026#34;Ola, $nome! Tudo bem?\u0026#34; } // Ou ainda mais enxuta com expressao fun saudacao(nome: String) = \u0026#34;Ola, $nome! Tudo bem?\u0026#34; fun main() { println(saudacao(nome)) } Repare como o código é limpo e fácil de ler. Sem ponto e vírgula obrigatório, sem declarações verbosas, sem getters e setters intermináveis.\nO que facilita o aprendizado Documentação excelente: o site oficial tem tutoriais passo a passo muito bem feitos Kotlin Playground: você testa código no navegador sem precisar instalar nada Mensagens de erro claras: o compilador do Kotlin é bastante amigável e te diz exatamente o que está errado Comunidade ativa: sempre tem alguém disposto a ajudar em fóruns e grupos A curva de aprendizado em detalhes Para ser mais específico, dá pra dividir o aprendizado de Kotlin em fases bem definidas. Cada fase tem seu próprio nível de desafio:\nFase 1 \u0026ndash; Fundamentos (2 a 4 semanas): aqui você aprende variáveis, tipos básicos, estruturas condicionais, loops e funções. Essa etapa é bem tranquila, especialmente se você já programou em qualquer outra linguagem. O guia completo de Kotlin cobre tudo isso de forma detalhada.\nFase 2 \u0026ndash; Orientação a objetos (2 a 4 semanas): classes, herança, interfaces, data classes e sealed classes. Se você vem de Java, vai se sentir em casa. Se vem de Python ou JavaScript, vai precisar de um pouco mais de atenção.\nFase 3 \u0026ndash; Recursos intermediários (3 a 6 semanas): lambdas, extension functions, collections e null safety. Aqui o Kotlin começa a mostrar sua personalidade. São conceitos poderosos que levam um tempo pra se tornarem naturais.\nFase 4 \u0026ndash; Tópicos avançados (4 a 8 semanas): coroutines, Flow, generics e DSLs. Essa é a fase que separa o júnior do pleno. Não é que seja impossível, mas exige mais dedicação e prática.\nOnde a coisa pode apertar Seria desonesto dizer que tudo são flores. Alguns conceitos podem dar um nó na cabeça de quem está começando:\nNull safety: entender o sistema de tipos anuláveis (String? vs String) exige um pouco de prática Coroutines: programação assíncrona é um tema avançado que leva um tempinho pra absorver Funções de extensão e lambdas: são recursos poderosos, mas podem confundir no início Generics: assim como em qualquer linguagem tipada, genéricos são um desafio O null safety, por exemplo, é algo que parece complicado no começo mas rapidamente se torna um dos recursos que você mais gosta. Depois que você se acostuma, programar em linguagens sem null safety parece perigoso. É como dirigir sem cinto de segurança: você até consegue, mas por que faria isso?\nComparando com outras linguagens Se a gente fosse fazer um ranking de dificuldade, Kotlin ficaria mais ou menos assim:\nMais fácil que: C++, Rust, Scala Nível parecido com: Swift, TypeScript Um pouco mais complexa que: Python (por causa da tipagem estática) Para quem vem de Java, a transição é muito suave. A maioria dos conceitos são os mesmos, mas com uma sintaxe mais enxuta. O que levava 50 linhas em Java pode ser feito em 10 linhas de Kotlin. Data classes, por exemplo, eliminam toneladas de boilerplate.\nPara quem vem de Python ou JavaScript, o maior ajuste é a tipagem estática. Você precisa declarar (ou deixar o compilador inferir) o tipo das variáveis. No início pode parecer restritivo, mas com o tempo você percebe que isso evita muitos bugs que só apareceriam em produção.\nPara quem vem de Swift, a semelhança é impressionante. Ambas as linguagens foram criadas com filosofias parecidas \u0026ndash; segurança, concisão e expressividade. Se você sabe Swift, aprender Kotlin é quase como aprender um dialeto da mesma língua.\nDicas práticas para acelerar o aprendizado Além de seguir as fases descritas acima, algumas práticas ajudam bastante:\nEscreva código todo dia: nem que seja por 20 minutos. Consistência é mais importante que intensidade Use o Kotlin Playground: teste ideias rápidas sem precisar abrir uma IDE. É perfeito para experimentar lambdas, extension functions e outros recursos Leia código de outros: explorar projetos open source em Kotlin ensina padrões e boas práticas que nenhum curso ensina Construa algo real: um app pessoal, uma API simples com Ktor, um bot para Telegram. Projetos reais fixam o conhecimento de um jeito que exercícios artificiais não conseguem Participe da comunidade: tire dúvidas, responda perguntas de outros, participe de eventos. Ensinar é uma das melhores formas de aprender O nosso tutorial do primeiro programa Kotlin é um ótimo ponto de partida se você quer começar hoje mesmo.\nO segredo é a prática Como qualquer habilidade nova, aprender Kotlin exige dedicação e consistência. Não adianta maratonar um curso de 40 horas num fim de semana e achar que virou especialista. O ideal é estudar um pouquinho todo dia, escrever código e não ter medo de errar. Os erros são os melhores professores que existem.\nSe você está com receio de começar, deixa esse medo de lado. A curva de aprendizado do Kotlin é tranquila, e o retorno que a linguagem traz pra sua carreira compensa cada minuto de estudo. Para uma visão completa das boas práticas da linguagem, confira nosso tutorial dedicado ao tema.\n","permalink":"https://kotlin.dev.br/perguntas/kotlin-e-dificil/","summary":"\u003ch2 id=\"kotlin-é-difícil-de-aprender\"\u003eKotlin é difícil de aprender?\u003c/h2\u003e\n\u003cp\u003eVamos direto ao ponto: \u003cstrong\u003enão, Kotlin não é uma linguagem difícil de aprender\u003c/strong\u003e. Pelo contrário, ela foi projetada desde o início para ser clara, concisa e agradável de usar. Mas isso não quer dizer que não existam desafios pelo caminho.\u003c/p\u003e\n\u003ch3 id=\"por-que-kotlin-é-considerada-acessível\"\u003ePor que Kotlin é considerada acessível?\u003c/h3\u003e\n\u003cp\u003eA sintaxe do Kotlin foi pensada pra reduzir a \u0026ldquo;burocracia\u0026rdquo; que existe em outras linguagens. Veja como é simples declarar variáveis e criar funções:\u003c/p\u003e","title":"Kotlin É Difícil de Aprender? | Kotlin Brasil"},{"content":"Kotlin serve para quê? Muita gente acha que Kotlin é \u0026ldquo;só pra fazer app Android\u0026rdquo;, mas a realidade é bem diferente. A linguagem é incrivelmente versátil e pode ser usada em diversas áreas do desenvolvimento de software. Bora conhecer cada uma delas?\n1. Desenvolvimento Android Essa é a aplicação mais conhecida. Desde 2019, o Google recomenda Kotlin como linguagem principal para Android. O Jetpack Compose, framework moderno de UI, foi construído pensando em Kotlin. Praticamente todo app Android novo é feito com Kotlin hoje em dia.\nO desenvolvimento Android com Kotlin vai além de telas simples. A linguagem se integra perfeitamente com toda a stack do Android moderno: ViewModel para gerenciar estado, coroutines para operações assíncronas, Flow para streams de dados reativos, e Room para persistência local.\n// Exemplo de ViewModel com coroutines no Android class ProdutoViewModel( private val repositorio: ProdutoRepositorio ) : ViewModel() { private val _produtos = MutableStateFlow\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt;(emptyList()) val produtos: StateFlow\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt; = _produtos.asStateFlow() fun carregarProdutos() { viewModelScope.launch { val resultado = repositorio.buscarTodos() _produtos.value = resultado } } } Se quiser começar nessa área, confira nosso tutorial de primeiro app Android com Kotlin e o guia completo de Android com Kotlin.\n2. Backend / Servidor Kotlin brilha no desenvolvimento de APIs e microsserviços. Os frameworks mais populares são:\nKtor: framework assíncrono criado pela própria JetBrains Spring Boot: o queridinho do mundo Java funciona perfeitamente com Kotlin // Exemplo de API simples com Ktor fun Application.configurarRotas() { routing { get(\u0026#34;/api/saudacao/{nome}\u0026#34;) { val nome = call.parameters[\u0026#34;nome\u0026#34;] ?: \u0026#34;visitante\u0026#34; call.respondText(\u0026#34;E aí, $nome! Bem-vindo à API Kotlin!\u0026#34;) } get(\u0026#34;/api/status\u0026#34;) { call.respondText(\u0026#34;Servidor rodando de boas!\u0026#34;) } } } A escolha entre Ktor e Spring Boot depende do projeto. Ktor é mais leve e opinativo \u0026ndash; ideal para microsserviços e APIs menores. Spring Boot traz um ecossistema gigante com soluções prontas para segurança, mensageria, e integração com bancos de dados. Ambos oferecem suporte nativo a coroutines, o que significa alta performance com código limpo.\nPara se aprofundar, temos guias dedicados: backend com Ktor, backend com Spring, REST API com Kotlin e microsserviços.\n3. Kotlin Multiplatform (KMP) Essa é uma das áreas que mais cresce. Com KMP, você escreve a lógica de negócio uma vez e compartilha entre Android, iOS, web e desktop. Imagina o tanto de retrabalho que isso economiza em projetos grandes?\nNa prática, funciona assim: você cria um módulo compartilhado com a lógica de negócio, modelos de dados, chamadas de API e regras de válidação. Cada plataforma implementa apenas a camada de UI nativa. É diferente de soluções como Flutter ou React Native porque o KMP não tenta substituir a UI nativa \u0026ndash; ele compartilha apenas o que faz sentido.\nEmpresas como Netflix, Cash App e Philips já usam KMP em produção. Para começar, veja nosso tutorial de Kotlin Multiplatform e o guia de KMP Mobile.\n4. Desenvolvimento Web (Frontend) Com o Kotlin/JS, dá pra compilar Kotlin pra JavaScript e usar no frontend. Existem frameworks como o Kotlin/JS wrappers para React que permitem criar interfaces web usando Kotlin puro.\nA vantagem aqui é usar a mesma linguagem no frontend e no backend, compartilhando modelos de dados e válidações. Isso reduz erros de inconsistência e facilita a manutenção. Além disso, você ganha null safety e tipagem forte no frontend, coisa que JavaScript puro não oferece.\n5. Aplicações Desktop Através do Compose Multiplatform, é possível criar aplicações desktop nativas para Windows, macOS e Linux usando a mesma API do Jetpack Compose. Se você já conhece Composable e Modifier do desenvolvimento Android, a transição para desktop é quase imediata.\n// Exemplo de aplicacao desktop com Compose Multiplatform @Composable fun AppDesktop() { var contador by remember { mutableStateOf(0) } Column( modifier = Modifier.fillMaxSize().padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Text(\u0026#34;Cliques: $contador\u0026#34;, fontSize = 24.sp) Spacer(modifier = Modifier.height(16.dp)) Button(onClick = { contador++ }) { Text(\u0026#34;Incrementar\u0026#34;) } } } Confira nosso guia de Jetpack Compose para entender a fundo o modelo declarativo de UI.\n6. Scripting Kotlin também funciona como linguagem de script. Você pode criar arquivos .kts para automatizar tarefas, substituindo scripts Bash ou Python em alguns cenários:\n// build-helper.kts val arquivos = java.io.File(\u0026#34;./src\u0026#34;) .walkTopDown() .filter { it.extension == \u0026#34;kt\u0026#34; } .toList() println(\u0026#34;Encontrei ${arquivos.size} arquivos Kotlin no projeto\u0026#34;) Scripts Kotlin são especialmente úteis em projetos que já usam a linguagem, porque você mantém um ecossistema único. Arquivos Gradle com Kotlin DSL (.gradle.kts) são o exemplo mais comum disso na prática.\n7. Ciência de dados Com bibliotecas como Kotlin DataFrame e integração com Jupyter Notebooks, Kotlin vem ganhando espaço também na análise de dados. A tipagem forte da linguagem ajuda a evitar erros comuns em manipulação de datasets, e as collections de Kotlin oferecem operações funcionais poderosas como map, filter, groupBy e fold que facilitam transformações de dados.\n8. Testes automatizados Uma aplicação que merece destaque é o uso de Kotlin para escrever testes. Mesmo em projetos Java, muitas equipes escrevem os testes em Kotlin pela concisão da linguagem. Frameworks como JUnit 5 e Kotest funcionam muito bem com Kotlin, e as data classes tornam a criação de dados de teste extremamente prática.\nPara aprender mais sobre testes, veja o tutorial de testes unitários e o guia de testes em Kotlin.\nResumindo Kotlin não é uma linguagem de nicho. Ela serve pra praticamente tudo: mobile, backend, frontend, desktop, scripts e até ciência de dados. Essa versatilidade é um dos motivos pelos quais a linguagem continua crescendo no mercado brasileiro e mundial. Independente da área que você escolher, Kotlin tem algo a oferecer.\nSe quiser entender melhor a linguagem antes de escolher uma área, comece pelo nosso artigo O que é Kotlin? e pelo guia completo de Kotlin. Para ciência de dados e automação, Python é a escolha dominante. Já para backend de alta performance e microsserviços cloud-native, Go é uma alternativa popular.\n","permalink":"https://kotlin.dev.br/perguntas/kotlin-serve-para-que/","summary":"\u003ch2 id=\"kotlin-serve-para-quê\"\u003eKotlin serve para quê?\u003c/h2\u003e\n\u003cp\u003eMuita gente acha que Kotlin é \u0026ldquo;só pra fazer app Android\u0026rdquo;, mas a realidade é bem diferente. A linguagem é \u003cstrong\u003eincrivelmente versátil\u003c/strong\u003e e pode ser usada em diversas áreas do desenvolvimento de software. Bora conhecer cada uma delas?\u003c/p\u003e\n\u003ch3 id=\"1-desenvolvimento-android\"\u003e1. Desenvolvimento Android\u003c/h3\u003e\n\u003cp\u003eEssa é a aplicação mais conhecida. Desde 2019, o Google recomenda Kotlin como linguagem principal para Android. O \u003cstrong\u003eJetpack Compose\u003c/strong\u003e, framework moderno de UI, foi construído pensando em Kotlin. Praticamente todo app Android novo é feito com Kotlin hoje em dia.\u003c/p\u003e","title":"Kotlin Serve para Quê? | Kotlin Brasil"},{"content":"Kotlin ou Java: qual escolher? Essa é a dúvida que aparece em praticamente todo fórum de programação. E a verdade é que não existe uma resposta única \u0026ndash; depende do contexto. Mas vamos colocar os pingos nos is e te ajudar a decidir.\nO cenário atual Java existe desde 1995 e continua firme e forte no mercado. Kotlin surgiu em 2011 como uma alternativa mais moderna e produtiva. Ambas rodam na JVM e são interoperáveis, ou seja, dá pra misturar código das duas no mesmo projeto sem problema nenhum.\nEm 2026, o cenário é claro: Java continua dominante em grandes corporações e sistemas legados, enquanto Kotlin cresce rapidamente em projetos novos, especialmente em Android, backend moderno e desenvolvimento multiplataforma. Entender as forças de cada linguagem é essencial para tomar uma decisão informada.\nComparação na prática Veja a diferença ao criar uma classe simples de dados:\nJava:\npublic class Usuario { private String nome; private int idade; public Usuario(String nome, int idade) { this.nome = nome; this.idade = idade; } public String getNome() { return nome; } public int getIdade() { return idade; } @Override public String toString() { return \u0026#34;Usuario{nome=\u0026#39;\u0026#34; + nome + \u0026#34;\u0026#39;, idade=\u0026#34; + idade + \u0026#34;}\u0026#34;; } } Kotlin:\ndata class Usuario(val nome: String, val idade: Int) Uma linha em Kotlin faz o trabalho de mais de 15 linhas em Java. O data class já gera automaticamente toString(), equals(), hashCode() e copy(). Confira nosso tutorial de data classes para entender todos os detalhes.\nComparação detalhada Aspecto Java Kotlin Null safety Não tem (depende de anotações) Nativo no sistema de tipos Boilerplate Alto (getters, setters, constructors) Mínimo (data classes, inferência) Coroutines Não tem (usa threads ou frameworks) Suporte nativo Extension functions Não tem Sim Smart casts Não tem Sim Programação funcional Melhorou com Java 8+, mas limitada Suporte completo e idiomático Compilação Rápida Um pouco mais lenta (melhorando) Tempo no mercado Desde 1995 Desde 2011 (estável desde 2016) Suporte Android Suporte histórico Linguagem recomendada pelo Google Multiplataforma Não tem Kotlin Multiplatform Quando escolher Kotlin Desenvolvimento Android: o Google recomenda Kotlin como linguagem principal Projetos novos: se está começando do zero, Kotlin oferece mais produtividade Null safety: se você sofre com NullPointerException, Kotlin resolve isso no nível do compilador Projetos multiplataforma: Kotlin Multiplatform não tem equivalente em Java Para quem quer explorar o lado backend da linguagem, temos guias dedicados para Ktor e Spring Boot com Kotlin. E para desenvolvimento mobile, o guia de Jetpack Compose e o tutorial básico de Compose são ótimos pontos de partida.\nQuando escolher Java Projetos legados: muitas empresas têm bases de código enormes em Java Ecossistema enterprise: Java ainda domina em ambientes corporativos tradicionais Mais material de estudo: por ser mais antiga, tem mais conteúdo disponível Vagas de emprego: no Brasil, Java ainda tem mais vagas no total (embora as de Kotlin estejam crescendo rápido) Impacto na carreira Vamos ser práticos: se você está pensando em termos de carreira, considere o seguinte:\nPara quem está começando: aprender Kotlin primeiro pode ser vantajoso. A linguagem é mais moderna, tem menos armadilhas e te ensina boas práticas desde o início (como imutabilidade e null safety). Além disso, entender Kotlin facilita a transição para Java depois, já que os conceitos da JVM são compartilhados.\nPara quem já programa em Java: adicionar Kotlin ao seu repertório é um diferencial competitivo enorme. Muitas empresas brasileiras estão migrando ou iniciando projetos novos em Kotlin, e profissionais que dominam as duas linguagens são altamente valorizados. A curva de aprendizado é suave \u0026ndash; a maioria dos devs Java se sente confortável em Kotlin em poucas semanas. Veja nosso artigo sobre como aprender Kotlin para um roteiro prático.\nMercado brasileiro em 2026: fintechs como Nubank, bancos digitais, grandes varejistas e startups de tecnologia estão entre os maiores contratantes de Kotlin no Brasil. O salário médio de um dev Kotlin tende a ser competitivo, pois a demanda cresce mais rápido que a oferta de profissionais qualificados.\nDicas para migração de Java para Kotlin Se você ou seu time estão considerando a transição, aqui vão algumas estratégias que funcionam bem na prática:\nComece pelos testes: escrever testes unitários em Kotlin é uma forma segura de se familiarizar com a linguagem sem impactar código de produção. Nosso guia de testes em Kotlin e o tutorial de testes unitários podem ajudar nesse passo.\nConverta arquivos gradualmente: o IntelliJ IDEA tem uma função de conversão automática de Java para Kotlin (Ctrl+Alt+Shift+K). O resultado nem sempre é idiomático, mas é um bom ponto de partida.\nAdote Kotlin em novos módulos: defina que todo código novo será escrito em Kotlin. Isso evita a necessidade de parar tudo para migrar e permite que o time aprenda no ritmo certo.\nAproveite a interoperabilidade: Kotlin e Java convivem perfeitamente no mesmo projeto. Você pode chamar código Java a partir de Kotlin e vice-versa sem nenhuma fricção.\nPara entender melhor como funciona a construção de projetos mistos, confira nosso tutorial de Gradle com Kotlin e o guia de Gradle.\nA resposta sincera Se você está começando agora e quer focar em Android ou projetos modernos, vai de Kotlin sem pensar duas vezes. Se precisa trabalhar com sistemas legados ou ambientes enterprise tradicionais, Java ainda é essencial.\nO melhor dos mundos? Aprenda as duas. Como elas são interoperáveis e rodam na mesma plataforma, conhecer ambas te torna um profissional muito mais completo e valorizado no mercado. Muitos times brasileiros já trabalham com as duas linguagens no mesmo projeto, e ter essa flexibilidade é um diferencial enorme na hora de disputar uma vaga.\nPara dar o próximo passo, explore nosso guia completo de Kotlin e os diversos tutoriais disponíveis aqui no Kotlin Brasil.\n","permalink":"https://kotlin.dev.br/perguntas/kotlin-ou-java/","summary":"\u003ch2 id=\"kotlin-ou-java-qual-escolher\"\u003eKotlin ou Java: qual escolher?\u003c/h2\u003e\n\u003cp\u003eEssa é a dúvida que aparece em praticamente todo fórum de programação. E a verdade é que \u003cstrong\u003enão existe uma resposta única\u003c/strong\u003e \u0026ndash; depende do contexto. Mas vamos colocar os pingos nos is e te ajudar a decidir.\u003c/p\u003e\n\u003ch3 id=\"o-cenário-atual\"\u003eO cenário atual\u003c/h3\u003e\n\u003cp\u003eJava existe desde 1995 e continua firme e forte no mercado. Kotlin surgiu em 2011 como uma alternativa mais moderna e produtiva. Ambas rodam na JVM e são interoperáveis, ou seja, dá pra misturar código das duas no mesmo projeto sem problema nenhum.\u003c/p\u003e","title":"Kotlin ou Java: Qual Escolher? | Kotlin Brasil"},{"content":"Como aprender Kotlin em 2026? Se você decidiu que quer aprender Kotlin, parabéns pela escolha! Agora vem a pergunta que não quer calar: por onde começar? Calma que a gente te guia nessa jornada.\n1. Comece pelo básico da linguagem Antes de sair criando aplicativos, é fundamental entender os fundamentos. Dedique um tempo pra aprender:\nVariáveis (val e var) \u0026ndash; veja nosso artigo sobre a diferença entre val e var Tipos de dados e inferência de tipos \u0026ndash; confira o tutorial de variáveis e tipos Funções e funções de extensão Classes e objetos Null safety Coleções e lambdas O site oficial kotlinlang.org tem uma documentação impecável e é o melhor ponto de partida. Além disso, o Kotlin Koans é um conjunto de exercícios interativos que te ensina a linguagem na prática.\n2. Escolha um caminho Kotlin é versátil, então defina logo qual área te interessa mais:\nAndroid: se quer desenvolver apps, mergulhe no Jetpack Compose. Temos um tutorial básico de Jetpack Compose e um guia completo para te ajudar. Backend: explore frameworks como Ktor e Spring Boot com Kotlin. Veja nosso artigo sobre Kotlin para backend e os guias de Ktor e Spring Boot. Multiplataforma: conheça o Kotlin Multiplatform (KMP) com nosso tutorial de KMP e o guia de KMM. Não se preocupe em escolher \u0026ldquo;errado\u0026rdquo;. Os fundamentos da linguagem são os mesmos independente do caminho, e você pode mudar de área depois sem perder o que aprendeu.\n3. Pratique com projetos reais Nada substitui a mão na massa. Crie projetos simples e vá evoluindo:\n// Seu primeiro projetinho: uma lista de tarefas simples fun main() { val tarefas = mutableListOf\u0026lt;String\u0026gt;() tarefas.add(\u0026#34;Estudar Kotlin\u0026#34;) tarefas.add(\u0026#34;Criar meu primeiro app\u0026#34;) tarefas.add(\u0026#34;Contribuir com open source\u0026#34;) tarefas.forEachIndexed { indice, tarefa -\u0026gt; println(\u0026#34;${indice + 1}. $tarefa\u0026#34;) } println(\u0026#34;\\nTotal de tarefas: ${tarefas.size}\u0026#34;) } Depois desse primeiro passo, tente projetos progressivamente mais desafiadores:\nCalculadora de IMC: pratique funções, condicionais e entrada de dados Conversor de moedas: trabalhe com APIs externas e coroutines App de anotações: exercite persistência de dados com Room API REST simples: crie endpoints com Ktor ou Spring Boot A ideia é que cada projeto novo te force a aprender algo diferente. Não precisa ser nada grandioso \u0026ndash; o importante é resolver problemas reais e ver seu código funcionando.\n4. Plano de estudos sugerido Se você quer um roteiro mais estruturado, aqui vai uma sugestão de cronograma:\nSemanas 1-2: Fundamentos\nVariáveis, tipos e operadores Estruturas condicionais e loops Funções e parâmetros Primeiro programa funcionando \u0026ndash; veja nosso tutorial do primeiro programa Semanas 3-4: Orientação a objetos\nClasses e objetos Herança e interfaces Data classes e sealed classes Enums e companion objects Semanas 5-6: Kotlin idiomático\nColeções e transformações Lambdas e higher-order functions Extension functions Null safety na prática Semanas 7-8: Escolha sua especialização\nAndroid: Jetpack Compose básico e configuração do Android Studio Backend: Tutorial de Ktor ou Spring Boot Avançado: Coroutines e Flow Esse cronograma assume dedicação de pelo menos uma hora por dia. Se você puder dedicar mais tempo, pode acelerar. O importante é não pular etapas.\n5. Recursos recomendados em 2026 Documentação oficial: sempre atualizada e muito bem escrita Kotlin Playground: pra testar código sem instalar nada YouTube: canais brasileiros têm crescido bastante com conteúdo de Kotlin Comunidades: participe de grupos no Telegram, Discord e meetups locais Aqui no Kotlin Brasil: nosso conteúdo é pensado especialmente pra comunidade brasileira Além desses, vale explorar nosso guia completo de Kotlin, que serve como referência para consulta rápida, e os guias de testes e arquitetura para quando você avançar nos estudos.\n6. Dicas de ouro Não pule etapas: entenda bem os fundamentos antes de partir pro avançado Code todo dia: mesmo que sejam 30 minutinhos, a consistência faz toda a diferença Leia código de outros: explore projetos open source em Kotlin no GitHub Participe da comunidade: tire dúvidas, ajude outras pessoas e troque experiências 7. Participando da comunidade A comunidade Kotlin no Brasil tem crescido de forma consistente. Participar dela vai acelerar muito o seu aprendizado:\nGrupos no Telegram e Discord: existem grupos brasileiros ativos onde você pode tirar dúvidas e compartilhar descobertas. Não tenha vergonha de perguntar \u0026ndash; todo mundo já foi iniciante. Meetups e eventos: fique de olho em eventos presenciais e online sobre Kotlin. São ótimas oportunidades para fazer networking e aprender com quem já tem experiência. Contribuição open source: mesmo como iniciante, você pode contribuir com documentação, traduções ou correção de bugs simples. Isso acelera o aprendizado e enriquece o currículo. Escreva sobre o que aprende: criar artigos ou posts sobre seus estudos consolida o conhecimento e ajuda outros devs que estão no mesmo caminho. Quanto tempo leva? Depende da sua dedicação e experiência prévia. Quem já programa em Java consegue se sentir confortável em Kotlin em duas a quatro semanas. Pra quem está começando do zero, de dois a quatro meses já dá pra ter uma base sólida.\nSe você vem de outra linguagem como Python ou JavaScript, o tempo fica entre essas duas faixas. Os conceitos de programação que você já conhece vão se aplicar, mas a tipagem estática e alguns padrões da JVM podem exigir uma adaptação.\nO mais importante é manter a constância e não desistir nos primeiros obstáculos. Todo mundo passa por dificuldades no começo, e faz parte do processo de aprendizagem! Se bater aquela dúvida sobre Kotlin ou Java, temos um artigo dedicado a essa comparação.\n","permalink":"https://kotlin.dev.br/perguntas/como-aprender-kotlin/","summary":"\u003ch2 id=\"como-aprender-kotlin-em-2026\"\u003eComo aprender Kotlin em 2026?\u003c/h2\u003e\n\u003cp\u003eSe você decidiu que quer aprender Kotlin, parabéns pela escolha! Agora vem a pergunta que não quer calar: \u003cstrong\u003epor onde começar?\u003c/strong\u003e Calma que a gente te guia nessa jornada.\u003c/p\u003e\n\u003ch3 id=\"1-comece-pelo-básico-da-linguagem\"\u003e1. Comece pelo básico da linguagem\u003c/h3\u003e\n\u003cp\u003eAntes de sair criando aplicativos, é fundamental entender os fundamentos. Dedique um tempo pra aprender:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eVariáveis (\u003ccode\u003eval\u003c/code\u003e e \u003ccode\u003evar\u003c/code\u003e) \u0026ndash; veja nosso artigo sobre a \u003ca href=\"/perguntas/diferenca-val-var/\"\u003ediferença entre val e var\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eTipos de dados e inferência de tipos \u0026ndash; confira o \u003ca href=\"/tutoriais/variaveis-e-tipos/\"\u003etutorial de variáveis e tipos\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eFunções e \u003ca href=\"/glossario/extension-function/\"\u003efunções de extensão\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"/glossario/class/\"\u003eClasses\u003c/a\u003e e objetos\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"/glossario/nullable/\"\u003eNull safety\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"/glossario/collections/\"\u003eColeções\u003c/a\u003e e \u003ca href=\"/glossario/lambda/\"\u003elambdas\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eO site oficial \u003ca href=\"https://kotlinlang.org/docs/getting-started.html\"\u003ekotlinlang.org\u003c/a\u003e tem uma documentação impecável e é o melhor ponto de partida. Além disso, o \u003cstrong\u003eKotlin Koans\u003c/strong\u003e é um conjunto de exercícios interativos que te ensina a linguagem na prática.\u003c/p\u003e","title":"Como Aprender Kotlin em 2026? | Kotlin Brasil"},{"content":"Jetpack Compose é o toolkit moderno do Google para construir interfaces nativas no Android usando Kotlin. Em vez de manipular Views com XML, você descreve sua UI de forma declarativa com funções Composable. Neste tutorial, vamos explorar os fundamentos do Jetpack Compose e entender como ele revoluciona o desenvolvimento de interfaces Android. Se você está começando com Android ou migrando de XML, este guia vai apresentar tudo o que precisa saber.\nO que é Programação Declarativa de UI? No paradigma imperativo tradicional do Android (XML + Views), você define a UI em arquivos XML e depois manipula cada componente programaticamente, alterando propriedades e respondendo a eventos. Isso frequentemente resulta em código verboso e propenso a bugs, pois você precisa manter a UI sincronizada manualmente com o estado da aplicação.\nCom o Jetpack Compose, você adota o paradigma declarativo: em vez de dizer ao framework como atualizar a UI, você declara como ela deve parecer para cada estado. Quando o estado muda, o Compose automaticamente recompõe (recomposes) apenas os componentes afetados, garantindo que a UI sempre reflita o estado atual.\nUma função Composable é marcada com a annotation @Composable e descreve um pedaço da interface. Composables podem chamar outros Composables, formando uma árvore de componentes.\nimport androidx.compose.material3.Text import androidx.compose.runtime.Composable @Composable fun Saudacao(nome: String) { Text(text = \u0026#34;Olá, $nome! Bem-vindo ao Kotlin Brasil.\u0026#34;) } @Composable fun TelaPrincipal() { Saudacao(nome = \u0026#34;Maria\u0026#34;) } No exemplo acima, Saudacao é um Composable que recebe um parâmetro nome e exibe um texto formatado. O TelaPrincipal compõe a tela chamando Saudacao com um nome específico. Essa composição de funções é o coração do Jetpack Compose.\nGerenciamento de Estado com remember e mutableStateOf O estado é fundamental no Jetpack Compose. Quando um valor de estado muda, o Compose recompõe automaticamente todos os Composables que leem esse valor. Para criar e gerenciar estado dentro de um Composable, usamos remember e mutableStateOf.\nO remember preserva o valor entre recomposições, enquanto mutableStateOf cria um estado observável que dispara recomposição quando modificado.\nimport androidx.compose.foundation.layout.* import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @Composable fun Contador() { var contagem by remember { mutableStateOf(0) } Column( modifier = Modifier .fillMaxSize() .padding(32.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Text( text = \u0026#34;Contagem: $contagem\u0026#34;, style = MaterialTheme.typography.headlineLarge ) Spacer(modifier = Modifier.height(16.dp)) Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { Button(onClick = { contagem++ }) { Text(\u0026#34;Incrementar\u0026#34;) } OutlinedButton(onClick = { contagem-- }) { Text(\u0026#34;Decrementar\u0026#34;) } TextButton(onClick = { contagem = 0 }) { Text(\u0026#34;Resetar\u0026#34;) } } } } Neste exemplo, contagem é um estado local do Composable Contador. Cada vez que o usuário clica em um dos botões, o valor é atualizado e o Compose recompõe apenas os componentes que dependem de contagem, neste caso, o Text que exibe o número.\nO by é um operador de Delegação de propriedades em Kotlin. Ele delega o getter e setter da variável contagem ao MutableState\u0026lt;Int\u0026gt; retornado por mutableStateOf(0). Isso permite acessar e modificar o valor diretamente, sem precisar chamar .value explicitamente.\nÉ importante entender que remember só preserva o estado durante a vida do Composable na composição. Se o Composable for removido e adicionado novamente, ou se houver uma mudança de configuração (como rotação de tela), o estado será perdido. Para estado que precisa sobreviver a essas situações, use rememberSaveable ou ViewModel.\nComposables do Material Design 3 O Jetpack Compose inclui uma biblioteca completa de componentes Material Design 3, que oferece botões, campos de texto, cards, diálogos e muito mais, todos prontos para uso e personalizáveis.\nimport androidx.compose.foundation.layout.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.Share import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @OptIn(ExperimentalMaterial3Api::class) @Composable fun CartaoExemplo() { var expandido by remember { mutableStateOf(false) } Card( modifier = Modifier .fillMaxWidth() .padding(16.dp), elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) ) { Column(modifier = Modifier.padding(16.dp)) { Text( text = \u0026#34;Aprendendo Jetpack Compose\u0026#34;, style = MaterialTheme.typography.titleLarge ) Spacer(modifier = Modifier.height(8.dp)) Text( text = if (expandido) { \u0026#34;Jetpack Compose e o toolkit moderno para UI no Android. \u0026#34; + \u0026#34;Ele simplifica o desenvolvimento de interfaces com codigo \u0026#34; + \u0026#34;declarativo e reativo, eliminando a necessidade de XML.\u0026#34; } else { \u0026#34;Jetpack Compose e o toolkit moderno para UI no Android...\u0026#34; }, style = MaterialTheme.typography.bodyMedium ) Spacer(modifier = Modifier.height(12.dp)) Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { IconButton(onClick = { /* ação de favoritar */ }) { Icon(Icons.Default.Favorite, contentDescription = \u0026#34;Favoritar\u0026#34;) } IconButton(onClick = { /* ação de compartilhar */ }) { Icon(Icons.Default.Share, contentDescription = \u0026#34;Compartilhar\u0026#34;) } Spacer(modifier = Modifier.weight(1f)) TextButton(onClick = { expandido = !expandido }) { Text(if (expandido) \u0026#34;Ver menos\u0026#34; else \u0026#34;Ver mais\u0026#34;) } } } } } Os componentes do Material Design 3 seguem as diretrizes de design do Google e suportam temas dinâmicos (Dynamic Color) no Android 12+. Você pode personalizar cores, tipografia e formas através do MaterialTheme, que define o estilo visual de toda a aplicação.\nA anotação @OptIn(ExperimentalMaterial3Api::class) é necessária para usar APIs que ainda estão em fase experimental. Isso é comum em componentes mais recentes do Material Design 3.\nModifiers: Estilizando e Posicionando Composables Os Modifiers são a forma principal de estilizar e posicionar Composables no Jetpack Compose. Eles permitem definir tamanho, padding, margem, cor de fundo, borda, eventos de clique e muito mais. Os Modifiers são encadeados e a ordem importa.\nimport androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp @Composable fun ExemploModifiers() { Box( modifier = Modifier .fillMaxWidth() .padding(16.dp) .shadow(8.dp, RoundedCornerShape(12.dp)) .clip(RoundedCornerShape(12.dp)) .background(MaterialTheme.colorScheme.surface) .border(1.dp, Color.LightGray, RoundedCornerShape(12.dp)) .clickable { /* ação ao clicar */ } .padding(24.dp), contentAlignment = Alignment.Center ) { Text( text = \u0026#34;Modifiers são poderosos!\u0026#34;, style = MaterialTheme.typography.titleMedium ) } } A ordem dos Modifiers é crucial. No exemplo acima, o padding(16.dp) externo é aplicado antes do shadow e background, criando margem ao redor do Box. O padding(24.dp) interno é aplicado depois do background, criando espaço dentro do Box. Trocar a ordem dos Modifiers resulta em aparências completamente diferentes.\nOs Modifiers mais usados incluem fillMaxWidth(), fillMaxHeight(), fillMaxSize(), size(), padding(), background(), clickable(), clip() e weight() (dentro de Row/Column).\nDicas e Erros Comuns Não usar remember: sem remember, o estado é recriado a cada recomposição, resultando em componentes que parecem não responder a interações. Sempre envolva mutableStateOf com remember.\nComposables pesados dentro de LazyColumn: evite fazer operações pesadas (cálculos, formatações complexas) diretamente dentro de itens de LazyColumn. Pré-calcule os valores ou use remember para cachear resultados.\nIgnorar a ordem dos Modifiers: a ordem dos Modifiers afeta o resultado visual. padding antes de background cria margem; padding depois de background cria espaço interno. Experimente trocar a ordem para entender o comportamento.\nNão usar derivedStateOf: quando um estado depende de outro (ex: filtrar uma lista baseado em um texto de busca), use derivedStateOf para evitar recomposições desnecessárias.\nEsquecer contentDescription em ícones: para acessibilidade, sempre forneça uma descrição para ícones e imagens. Isso permite que leitores de tela descrevam o conteúdo para usuários com deficiência visual.\nConclusão e Próximos Passos Neste tutorial, você aprendeu os fundamentos do Jetpack Compose: funções Composable, gerenciamento de estado com remember e mutableStateOf, componentes Material Design 3 e o sistema de Modifiers. Esses conceitos formam a base para construir qualquer interface Android moderna.\nO Jetpack Compose é o futuro do desenvolvimento de UI no Android, e dominá-lo é essencial para qualquer desenvolvedor Kotlin. A abordagem declarativa simplifica o código, reduz bugs relacionados ao estado e torna o desenvolvimento mais produtivo.\nPara continuar sua jornada com Jetpack Compose, recomendamos:\nLayouts com Jetpack Compose para dominar Row, Column, Box e layouts avançados Primeiro App Android com Kotlin para aplicar Compose em um projeto completo Coroutines Avançadas: Flow e Channel para integrar Flow com Compose Delegação de Propriedades para entender melhor o by usado com remember ","permalink":"https://kotlin.dev.br/tutoriais/jetpack-compose-basico/","summary":"\u003cp\u003eJetpack Compose é o toolkit moderno do Google para construir interfaces nativas no Android usando Kotlin. Em vez de manipular Views com XML, você descreve sua UI de forma declarativa com funções Composable. Neste tutorial, vamos explorar os fundamentos do Jetpack Compose e entender como ele revoluciona o desenvolvimento de interfaces Android. Se você está começando com Android ou migrando de XML, este guia vai apresentar tudo o que precisa saber.\u003c/p\u003e","title":"Jetpack Compose: Introdução Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Kotlin é gratuito? Essa é uma das primeiras dúvidas de quem está conhecendo a linguagem, e a resposta é direta: sim, Kotlin é 100% gratuito e open source. Pode ficar tranquilo que você não vai precisar desembolsar nenhum centavo pra começar a programar.\nLicença open source Kotlin é distribuído sob a licença Apache 2.0, uma das licenças de código aberto mais permissivas que existem. Na prática, isso significa que você pode:\nUsar Kotlin em projetos pessoais e comerciais sem restrição Modificar o código-fonte da linguagem Distribuir suas modificações Usar em produtos proprietários sem precisar abrir seu código O código-fonte completo do Kotlin está disponível no GitHub da JetBrains, e qualquer pessoa pode contribuir com melhorias e correções.\nE as ferramentas de desenvolvimento? Aqui é onde muita gente se confunde. A JetBrains oferece o IntelliJ IDEA em duas versões:\nCommunity Edition: gratuita e já vem com suporte completo a Kotlin Ultimate Edition: paga, com recursos extras voltados para desenvolvimento web e enterprise Para programar em Kotlin, a versão gratuita resolve perfeitamente. Além disso, você também pode usar o Android Studio (que é baseado no IntelliJ e é gratuito) ou até mesmo o VS Code com extensões para Kotlin.\nSe quiser testar a linguagem sem instalar nada, o Kotlin Playground permite escrever e executar código direto no navegador:\nfun main() { val ferramentas = listOf( \u0026#34;IntelliJ IDEA Community\u0026#34; to \u0026#34;Gratuito\u0026#34;, \u0026#34;Android Studio\u0026#34; to \u0026#34;Gratuito\u0026#34;, \u0026#34;VS Code + extensao\u0026#34; to \u0026#34;Gratuito\u0026#34;, \u0026#34;Kotlin Playground\u0026#34; to \u0026#34;Gratuito\u0026#34; ) ferramentas.forEach { (nome, preco) -\u0026gt; println(\u0026#34;$nome -\u0026gt; $preco\u0026#34;) } } O ecossistema completo de ferramentas gratuitas Além das IDEs, o ecossistema Kotlin conta com uma série de ferramentas gratuitas que cobrem todas as etapas do desenvolvimento:\nBuild e gerenciamento de dependências: o Gradle é a ferramenta padrão para projetos Kotlin. Ele é gratuito, open source, e suporta o Kotlin DSL para configuração dos scripts de build. O Maven também funciona bem com Kotlin, caso você prefira.\nFrameworks para backend: tanto o Ktor (da própria JetBrains) quanto o Spring Boot são gratuitos e amplamente utilizados. Com eles você consegue criar APIs REST completas sem gastar nada.\nFrameworks para mobile: o Jetpack Compose do Google é totalmente gratuito e já é a forma recomendada de construir interfaces no Android. O Android Studio inclui emuladores, debugger e profiler \u0026ndash; tudo sem custo.\nFerramentas de teste: frameworks como JUnit, MockK e Turbine são todos open source. O guia de testes em Kotlin mostra como configurar tudo isso no seu projeto.\nCI/CD: ferramentas como GitHub Actions oferecem planos gratuitos generosos para projetos open source e repositórios privados. O guia de CI/CD com Kotlin explica como configurar pipelines automatizados.\nRecursos gratuitos para aprender O custo zero se estende também aos materiais de estudo. A comunidade Kotlin produz uma quantidade enorme de conteúdo gratuito e de qualidade:\nDocumentação oficial: o site kotlinlang.org tem uma das documentações mais completas e bem escritas do mundo da programação. Inclui tutoriais interativos, exemplos de código e guias por tópico Kotlin Koans: exercícios interativos dentro da própria IDE que ensinam os recursos da linguagem na prática. Cada exercício apresenta um conceito e pede que você escreva a solução Cursos no YouTube: canais brasileiros e internacionais oferecem cursos completos de Kotlin sem cobrar nada Nosso site: aqui no kotlin.dev.br você encontra tutoriais, guias e um glossário completo da linguagem, tudo em português Para quem está começando do zero, o tutorial do primeiro programa Kotlin ensina a configurar o ambiente e escrever seu primeiro código em poucos minutos.\nA comunidade open source Um dos aspectos mais valiosos do ecossistema Kotlin é a comunidade. Por ser open source, a linguagem atrai desenvolvedores do mundo todo que contribuem com bibliotecas, ferramentas e conteúdo educacional.\nBibliotecas essenciais como kotlinx.coroutines (para coroutines e programação assíncrona), kotlinx.serialization (para serialização de dados) e Ktor (para rede) são todas mantidas de forma aberta. Você pode inspecionar o código, reportar bugs e até enviar contribuições.\nNo Brasil, a comunidade Kotlin tem crescido de forma constante. Grupos no Telegram, canais no Discord e meetups presenciais conectam desenvolvedores de todos os níveis. É um ambiente acolhedor para quem está começando e quer tirar dúvidas sobre funções, lambdas, collections ou qualquer outro tópico.\nE no ambiente corporativo? Mesmo em ambientes corporativos, usar Kotlin não gera custo de licenciamento. Muitas empresas brasileiras já adotaram a linguagem justamente por esse motivo: além de ser moderna e produtiva, não tem custo de licença. O investimento fica por conta da capacitação do time, não da ferramenta.\nEmpresas que usam Spring Boot no backend, por exemplo, podem migrar gradualmente de Java para Kotlin sem nenhum custo adicional de ferramentas. O guia de Spring Boot com Kotlin mostra como essa transição funciona na prática. Da mesma forma, times de Android que já usam Android Studio não precisam de nenhuma ferramenta extra para começar a escrever Kotlin.\nResumindo Não existe desculpa financeira pra não aprender Kotlin. A linguagem, o compilador, as ferramentas de desenvolvimento e até ambientes online de teste são todos gratuitos. É só abrir o computador e começar a codar. A comunidade Kotlin é super acolhedora e vai te receber de braços abertos, independente do seu nível de experiência.\nSe você quer dar o primeiro passo agora mesmo, o tutorial de variáveis e tipos é uma ótima porta de entrada. E se preferir uma visão geral antes de mergulhar no código, o guia completo de Kotlin apresenta a linguagem de forma abrangente.\n","permalink":"https://kotlin.dev.br/perguntas/kotlin-e-gratuito/","summary":"\u003ch2 id=\"kotlin-é-gratuito\"\u003eKotlin é gratuito?\u003c/h2\u003e\n\u003cp\u003eEssa é uma das primeiras dúvidas de quem está conhecendo a linguagem, e a resposta é direta: \u003cstrong\u003esim, Kotlin é 100% gratuito e open source\u003c/strong\u003e. Pode ficar tranquilo que você não vai precisar desembolsar nenhum centavo pra começar a programar.\u003c/p\u003e\n\u003ch3 id=\"licença-open-source\"\u003eLicença open source\u003c/h3\u003e\n\u003cp\u003eKotlin é distribuído sob a \u003cstrong\u003elicença Apache 2.0\u003c/strong\u003e, uma das licenças de código aberto mais permissivas que existem. Na prática, isso significa que você pode:\u003c/p\u003e","title":"Kotlin É Gratuito? | Kotlin Brasil"},{"content":"O que é Kotlin? Se você está começando no mundo da programação ou já tem uma certa experiência, com certeza já esbarrou no nome Kotlin por aí. Mas afinal, o que é essa linguagem e por que tanta gente está falando dela?\nKotlin é uma linguagem de programação moderna, concisa e segura, criada pela JetBrains em 2011 e que teve sua primeira versão estável lançada em 2016. A JetBrains é a mesma empresa por trás do IntelliJ IDEA, um dos editores de código mais populares do mercado.\nPor que Kotlin faz tanto sucesso? O grande pulo do gato é que Kotlin roda na JVM (Java Virtual Machine), o que significa que ela é totalmente interoperável com Java. Ou seja, você pode usar bibliotecas Java dentro de um projeto Kotlin sem dor de cabeça nenhuma. Em 2019, o Google declarou Kotlin como a linguagem preferencial para desenvolvimento Android, e isso fez a adoção disparar de vez.\nMas Kotlin não para no Android. Hoje ela é usada para backend, frontend web, aplicações multiplataforma e até scripts. A versatilidade é um dos seus maiores trunfos. Se quiser conhecer todos os cenários de uso, confira nosso artigo sobre para que serve Kotlin.\nCaracterísticas principais Concisa: você escreve menos código para fazer a mesma coisa que faria em Java. Segura: o sistema de tipos ajuda a evitar aquele famoso NullPointerException. Interoperável: funciona lado a lado com código Java sem nenhum problema. Multiplataforma: com o Kotlin Multiplatform, dá pra compartilhar código entre Android, iOS, web e desktop. Um exemplo rápido Veja como é simples escrever um \u0026ldquo;Olá, mundo!\u0026rdquo; em Kotlin:\nfun main() { val nome = \u0026#34;Brasil\u0026#34; println(\u0026#34;Olá, $nome! Bem-vindo ao mundo Kotlin!\u0026#34;) } Repare que não precisamos de ponto e vírgula no final das linhas, nem de declarar o tipo da variável explicitamente. O compilador já resolve isso pra gente através da inferência de tipos.\nRecursos da linguagem que fazem a diferença Além das características gerais, Kotlin traz uma série de recursos que tornam o dia a dia do desenvolvedor muito mais produtivo.\nNull Safety \u0026ndash; O sistema de tipos de Kotlin diferencia referências que podem ser nulas das que nunca serão. Isso elimina boa parte dos erros em tempo de execução que são comuns em Java. Para saber mais, veja nosso glossário sobre nullable e o tutorial de null safety.\nvar cidade: String = \u0026#34;São Paulo\u0026#34; // nunca pode ser null var estado: String? = null // pode ser null // O compilador obriga voce a tratar o null antes de usar val tamanho = estado?.length ?: 0 Data Classes \u0026ndash; Criar classes que servem basicamente para armazenar dados fica ridiculamente simples. O compilador gera automaticamente equals(), hashCode(), toString() e copy():\ndata class Usuario(val nome: String, val email: String, val idade: Int) val usuario = Usuario(\u0026#34;Ana\u0026#34;, \u0026#34;ana@email.com\u0026#34;, 28) println(usuario) // Usuario(nome=Ana, email=ana@email.com, idade=28) Temos um tutorial completo sobre data classes se quiser se aprofundar.\nExtension Functions \u0026ndash; Permitem adicionar funcionalidades a classes existentes sem precisar herdá-las. Isso é muito poderoso para deixar o código mais expressivo. Confira o glossário de extension function e o tutorial prático.\nfun String.contarPalavras(): Int = this.split(\u0026#34; \u0026#34;).size val frase = \u0026#34;Kotlin é uma linguagem incrível\u0026#34; println(frase.contarPalavras()) // 5 Coroutines \u0026ndash; Para trabalhar com programação assíncrona, Kotlin oferece as coroutines, que são muito mais leves que threads tradicionais. Saiba mais no nosso artigo sobre o que são coroutines.\nO ecossistema Kotlin Kotlin não é apenas uma linguagem \u0026ndash; é um ecossistema completo. Aqui estão alguns pilares importantes:\nGradle com Kotlin DSL: a maioria dos projetos Kotlin usa Gradle como ferramenta de build, e o suporte a Kotlin DSL permite configurar builds de forma tipada e segura. Ktor: framework assíncrono para criar APIs e servidores web, desenvolvido pela própria JetBrains. Veja nosso guia de backend com Ktor. Spring Boot: um dos frameworks mais usados no mundo Java funciona perfeitamente com Kotlin. Confira o guia de backend com Spring. Jetpack Compose: framework declarativo para construir interfaces no Android e desktop. Temos um guia completo de Jetpack Compose. Kotlin Multiplatform: permite compartilhar código entre diferentes plataformas. Veja o tutorial de Kotlin Multiplatform. Quem usa Kotlin? Grandes empresas adotaram Kotlin nos seus projetos, incluindo Google, Netflix, Amazon, Pinterest e Uber. No Brasil, a comunidade também vem crescendo bastante, com cada vez mais vagas pedindo conhecimento na linguagem.\nAlém das gigantes de tecnologia, bancos e fintechs brasileiras vêm adotando Kotlin tanto no desenvolvimento Android quanto no backend. Empresas como Nubank, iFood e PicPay utilizam Kotlin em partes significativas das suas stacks. O mercado de trabalho para desenvolvedores Kotlin no Brasil segue aquecido, com salários competitivos tanto para posições mobile quanto para backend.\nKotlin vs. Java: qual escolher? Essa é uma pergunta que aparece bastante. A verdade é que as duas linguagens se complementam mais do que competem. Kotlin foi projetada para resolver pontos fracos do Java \u0026ndash; código verboso, null safety ausente, falta de recursos modernos \u0026ndash; mantendo total compatibilidade. Se você já sabe Java, a transição para Kotlin é bem suave. Se está começando do zero, Kotlin oferece uma curva de aprendizado mais amigável.\nPara um panorama completo de como começar, dê uma olhada no nosso guia completo de Kotlin.\nVale a pena aprender? Com toda certeza. Kotlin é uma linguagem que veio pra ficar, com uma comunidade ativa, documentação excelente e um ecossistema que não para de evoluir. Se você quer se manter relevante no mercado de desenvolvimento, aprender Kotlin é uma decisão muito inteligente.\nSe quiser dar os primeiros passos agora mesmo, confira nosso tutorial primeiro programa em Kotlin e o guia de como instalar Kotlin no seu computador.\nNos próximos artigos aqui do Kotlin Brasil, vamos nos aprofundar em cada aspecto da linguagem. Fique ligado!\n","permalink":"https://kotlin.dev.br/perguntas/o-que-e-kotlin/","summary":"\u003ch2 id=\"o-que-é-kotlin\"\u003eO que é Kotlin?\u003c/h2\u003e\n\u003cp\u003eSe você está começando no mundo da programação ou já tem uma certa experiência, com certeza já esbarrou no nome \u003cstrong\u003eKotlin\u003c/strong\u003e por aí. Mas afinal, o que é essa linguagem e por que tanta gente está falando dela?\u003c/p\u003e\n\u003cp\u003eKotlin é uma \u003cstrong\u003elinguagem de programação moderna, concisa e segura\u003c/strong\u003e, criada pela \u003ca href=\"https://www.jetbrains.com/\"\u003eJetBrains\u003c/a\u003e em 2011 e que teve sua primeira versão estável lançada em 2016. A JetBrains é a mesma empresa por trás do IntelliJ IDEA, um dos editores de código mais populares do mercado.\u003c/p\u003e","title":"O que É Kotlin? | Kotlin Brasil"},{"content":"Criar seu primeiro aplicativo Android com Kotlin é uma experiência empolgante e recompensadora. Neste tutorial, vamos construir juntos um app de lista de tarefas (To-Do List) completo, utilizando Jetpack Compose para a interface e conceitos fundamentais de Kotlin. Ao final, você terá uma aplicação funcional e entenderá os conceitos básicos do desenvolvimento Android moderno.\nPlanejando o App de Lista de Tarefas Antes de escrever qualquer código, é importante planejar o que nosso app vai fazer. Nosso To-Do List terá as seguintes funcionalidades: adicionar novas tarefas, marcar tarefas como concluídas, remover tarefas da lista e exibir a lista atualizada em tempo real.\nA arquitetura que vamos seguir é simples, mas segue as boas práticas recomendadas pelo Google. Teremos uma Activity principal que hospeda nossa UI em Jetpack Compose, uma class de dados para representar cada tarefa é um ViewModel para gerenciar o estado da aplicação.\nCertifique-se de que você já tem o Android Studio configurado conforme nosso tutorial de Configurando Kotlin no Android Studio. Com o ambiente pronto, crie um novo projeto com o template \u0026ldquo;Empty Activity\u0026rdquo; é o nome \u0026ldquo;ListaDeTarefas\u0026rdquo;.\nCriando o Modelo de Dados O primeiro passo é definir a estrutura de dados que representa uma tarefa. Em Kotlin, usamos Data Classes para isso, pois elas geram automaticamente métodos como equals(), hashCode(), toString() e copy().\n// modelo/Tarefa.kt package com.exemplo.listadetarefas.modelo import java.util.UUID data class Tarefa( val id: String = UUID.randomUUID().toString(), val titulo: String, val descricao: String = \u0026#34;\u0026#34;, val concluida: Boolean = false ) Note que usamos val para declarar propriedades imutáveis. O id é gerado automaticamente usando UUID, garantindo que cada tarefa tenha um identificador único. A descricao e concluida possuem valores padrão, tornando a criação de tarefas mais simples.\nA imutabilidade é uma prática recomendada em Kotlin. Em vez de modificar um objeto existente, criamos uma nova cópia com as alterações desejadas usando o método copy() da Data Class.\nImplementando o ViewModel O ViewModel é responsável por gerenciar o estado da nossa lista de tarefas. Ele sobrevive a mudanças de configuração (como rotação de tela) e fornece os dados para a UI de forma reativa usando StateFlow.\n// viewmodel/TarefaViewModel.kt package com.exemplo.listadetarefas.viewmodel import androidx.lifecycle.ViewModel import com.exemplo.listadetarefas.modelo.Tarefa import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update class TarefaViewModel : ViewModel() { private val _tarefas = MutableStateFlow\u0026lt;List\u0026lt;Tarefa\u0026gt;\u0026gt;(emptyList()) val tarefas: StateFlow\u0026lt;List\u0026lt;Tarefa\u0026gt;\u0026gt; = _tarefas.asStateFlow() fun adicionarTarefa(titulo: String, descricao: String = \u0026#34;\u0026#34;) { if (titulo.isBlank()) return val novaTarefa = Tarefa(titulo = titulo.trim(), descricao = descricao.trim()) _tarefas.update { listaAtual -\u0026gt; listaAtual + novaTarefa } } fun alternarConclusao(tarefaId: String) { _tarefas.update { listaAtual -\u0026gt; listaAtual.map { tarefa -\u0026gt; if (tarefa.id == tarefaId) { tarefa.copy(concluida = !tarefa.concluida) } else { tarefa } } } } fun removerTarefa(tarefaId: String) { _tarefas.update { listaAtual -\u0026gt; listaAtual.filter { it.id != tarefaId } } } val totalTarefas: Int get() = _tarefas.value.size val tarefasConcluidas: Int get() = _tarefas.value.count { it.concluida } } Observe como usamos Lambda expressions e Higher-Order Functions como map, filter e count para manipular a lista de tarefas. Essas são funcionalidades poderosas de Kotlin que tornam o código mais conciso e legível.\nO MutableStateFlow é usado internamente para permitir atualizações, enquanto o StateFlow exposto publicamente é somente leitura, seguindo o princípio de encapsulamento.\nConstruindo a Interface com Jetpack Compose Agora vamos criar a interface do nosso app usando Jetpack Compose. A UI será composta por um campo de texto para adicionar tarefas e uma lista rolável que exibe as tarefas existentes.\n// ui/TelaPrincipal.kt package com.exemplo.listadetarefas.ui import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Delete import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import com.exemplo.listadetarefas.modelo.Tarefa import com.exemplo.listadetarefas.viewmodel.TarefaViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable fun TelaPrincipal(viewModel: TarefaViewModel) { val tarefas by viewModel.tarefas.collectAsState() var novoTitulo by remember { mutableStateOf(\u0026#34;\u0026#34;) } Scaffold( topBar = { TopAppBar( title = { Text(\u0026#34;Lista de Tarefas\u0026#34;) }, colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.primaryContainer ) ) } ) { paddingValues -\u0026gt; Column( modifier = Modifier .fillMaxSize() .padding(paddingValues) .padding(16.dp) ) { Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { OutlinedTextField( value = novoTitulo, onValueChange = { novoTitulo = it }, label = { Text(\u0026#34;Nova tarefa\u0026#34;) }, modifier = Modifier.weight(1f), singleLine = true ) Spacer(modifier = Modifier.width(8.dp)) IconButton( onClick = { viewModel.adicionarTarefa(novoTitulo) novoTitulo = \u0026#34;\u0026#34; } ) { Icon(Icons.Default.Add, contentDescription = \u0026#34;Adicionar\u0026#34;) } } Spacer(modifier = Modifier.height(16.dp)) Text( text = \u0026#34;Total: ${tarefas.size} | Concluídas: ${tarefas.count { it.concluida }}\u0026#34;, style = MaterialTheme.typography.bodyMedium ) Spacer(modifier = Modifier.height(8.dp)) LazyColumn { items(tarefas, key = { it.id }) { tarefa -\u0026gt; CartaoTarefa( tarefa = tarefa, onAlternar = { viewModel.alternarConclusao(tarefa.id) }, onRemover = { viewModel.removerTarefa(tarefa.id) } ) } } } } } @Composable fun CartaoTarefa( tarefa: Tarefa, onAlternar: () -\u0026gt; Unit, onRemover: () -\u0026gt; Unit ) { Card( modifier = Modifier .fillMaxWidth() .padding(vertical = 4.dp) ) { Row( modifier = Modifier .fillMaxWidth() .padding(12.dp), verticalAlignment = Alignment.CenterVertically ) { Checkbox( checked = tarefa.concluida, onCheckedChange = { onAlternar() } ) Text( text = tarefa.titulo, modifier = Modifier.weight(1f), textDecoration = if (tarefa.concluida) { TextDecoration.LineThrough } else { TextDecoration.None } ) IconButton(onClick = onRemover) { Icon(Icons.Default.Delete, contentDescription = \u0026#34;Remover\u0026#34;) } } } } O Jetpack Compose usa o paradigma declarativo: descrevemos como a UI deve parecer para cada estado, e o framework cuida de atualizar a tela automaticamente quando o estado muda. O collectAsState() converte nosso StateFlow em um estado observável pelo Compose.\nConectando Tudo na MainActivity Por fim, precisamos conectar o ViewModel à nossa tela principal na MainActivity. O Android fornece a função viewModel() para criar e gerenciar instâncias de ViewModel automaticamente.\n// MainActivity.kt package com.exemplo.listadetarefas import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.viewModels import com.exemplo.listadetarefas.ui.TelaPrincipal import com.exemplo.listadetarefas.ui.theme.ListaDeTarefasTheme import com.exemplo.listadetarefas.viewmodel.TarefaViewModel class MainActivity : ComponentActivity() { private val viewModel: TarefaViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ListaDeTarefasTheme { TelaPrincipal(viewModel = viewModel) } } } } O by viewModels() utiliza o padrão de Delegação do Kotlin para criar o ViewModel de forma lazy, ou seja, ele só é instanciado quando acessado pela primeira vez. Além disso, o ViewModel sobrevive a mudanças de configuração, como rotação de tela.\nDicas e Erros Comuns Estado perdido ao girar a tela: se você armazenar estado diretamente no Composable com remember, ele será perdido ao girar a tela. Use ViewModel para dados que precisam sobreviver a mudanças de configuração.\nLazyColumn sem key: sempre forneça uma key única para itens de LazyColumn. Sem ela, o Compose pode ter problemas ao reordenar ou remover itens, causando comportamentos estranhos na interface.\nNão usar collectAsState(): esquecer de converter o StateFlow com collectAsState() faz com que a UI não seja atualizada quando o estado muda.\nModificar estado fora do ViewModel: toda modificação de estado deve passar pelo ViewModel. Manipular dados diretamente no Composable viola o padrão de arquitetura e dificulta os testes.\nEsquecer o Modifier.fillMaxSize(): sem definir o tamanho dos componentes, a UI pode não ocupar o espaço esperado na tela.\nConclusão e Próximos Passos Parabéns! Você criou seu primeiro aplicativo Android com Kotlin. Nosso app de lista de tarefas, embora simples, demonstra conceitos fundamentais como Data Classes, ViewModel, StateFlow e Jetpack Compose. Esses são os pilares do desenvolvimento Android moderno.\nPara evoluir este projeto, você poderia adicionar persistência de dados com Room, salvar tema e filtros com DataStore Preferences, criar navegação entre telas com Navigation Compose, adicionar notificações e organizar categorias para as tarefas.\nPara continuar aprendendo, recomendamos os seguintes tutoriais:\nJetpack Compose: Introdução para aprofundar seus conhecimentos em UI declarativa Layouts com Jetpack Compose para criar interfaces mais complexas Coroutines Avançadas: Flow e Channel para entender melhor o StateFlow usado neste projeto Testes Unitários com Kotlin para aprender a testar seu ViewModel Android offline-first com Kotlin para transformar o app em um projeto mais próximo de produção ","permalink":"https://kotlin.dev.br/tutoriais/primeiro-app-android/","summary":"\u003cp\u003eCriar seu primeiro aplicativo Android com Kotlin é uma experiência empolgante e recompensadora. Neste tutorial, vamos construir juntos um app de lista de tarefas (To-Do List) completo, utilizando Jetpack Compose para a interface e conceitos fundamentais de Kotlin. Ao final, você terá uma aplicação funcional e entenderá os conceitos básicos do desenvolvimento Android moderno.\u003c/p\u003e\n\u003ch2 id=\"planejando-o-app-de-lista-de-tarefas\"\u003ePlanejando o App de Lista de Tarefas\u003c/h2\u003e\n\u003cp\u003eAntes de escrever qualquer código, é importante planejar o que nosso app vai fazer. Nosso To-Do List terá as seguintes funcionalidades: adicionar novas tarefas, marcar tarefas como concluídas, remover tarefas da lista e exibir a lista atualizada em tempo real.\u003c/p\u003e","title":"Primeiro App Android com Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Configurar o ambiente de desenvolvimento é o primeiro passo para começar a programar em Kotlin para Android. Neste tutorial, vamos guiá-lo por todo o processo de instalação e configuração do Android Studio, desde o download até a criação do seu primeiro projeto. Se você é iniciante ou está migrando de outra linguagem, este guia completo vai ajudá-lo a começar com o pé direito.\nPré-requisitos e Download do Android Studio Antes de começar, verifique se seu computador atende aos requisitos mínimos para rodar o Android Studio. Você precisará de pelo menos 8 GB de RAM (16 GB recomendado), 8 GB de espaço em disco disponível é um processador moderno com suporte a virtualização para o emulador Android.\nAcesse o site oficial do Android Studio em developer.android.com/studio e faça o download da versão mais recente. O Android Studio está disponível para Windows, macOS e Linux. A instalação é simples e guiada por um assistente que configura automaticamente o Android SDK, o build system Gradle e outras ferramentas necessárias.\nDurante a instalação, o assistente perguntará sobre o tipo de instalação. Escolha \u0026ldquo;Standard\u0026rdquo; para que todas as configurações padrão sejam aplicadas automaticamente. Isso inclui o Android SDK, o emulador Android e as ferramentas de build necessárias. A instalação padrão costuma ocupar entre 4 e 8 GB de disco, dependendo dos componentes selecionados.\nApós a instalação, abra o Android Studio e permita que ele faça o download de componentes adicionais. Isso pode levar alguns minutos, dependendo da velocidade da sua conexão de internet.\nCriando seu Primeiro Projeto Kotlin Com o Android Studio instalado e configurado, vamos criar o primeiro projeto. Clique em \u0026ldquo;New Project\u0026rdquo; na tela inicial. Você verá uma lista de templates disponíveis. Para este tutorial, selecione \u0026ldquo;Empty Activity\u0026rdquo; e clique em \u0026ldquo;Next\u0026rdquo;.\nNa tela de configuração do projeto, preencha os seguintes campos:\nName: o nome do seu aplicativo (ex: \u0026ldquo;MeuPrimeiroApp\u0026rdquo;) Package name: o identificador único do app (ex: \u0026ldquo;com.exemplo.meuprimeiro\u0026rdquo;) Save location: onde o projeto será salvo no disco Language: selecione Kotlin Minimum SDK: escolha API 24 (Android 7.0) para cobrir a maioria dos dispositivos Clique em \u0026ldquo;Finish\u0026rdquo; e aguarde o Android Studio criar a estrutura do projeto e sincronizar o Gradle. Esse processo pode levar alguns minutos na primeira vez, pois o Gradle precisa baixar todas as dependências do projeto.\nAo final, você terá um projeto com a seguinte estrutura básica:\n// app/src/main/java/com/exemplo/meuprimeiro/MainActivity.kt package com.exemplo.meuprimeiro import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.material3.Text class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Text(text = \u0026#34;Olá, Kotlin Brasil!\u0026#34;) } } } Esse é o ponto de entrada da sua aplicação Android. A class MainActivity herda de ComponentActivity e sobrescreve o método onCreate, que é chamado quando a Activity é criada. O setContent define o conteúdo da tela usando Jetpack Compose.\nConfigurando o Gradle com Kotlin O Gradle é o sistema de build utilizado pelo Android Studio. Nos projetos modernos, o Gradle utiliza arquivos .kts (Kotlin Script) em vez dos tradicionais .gradle (Groovy). Vamos entender a estrutura dos arquivos de configuração.\nO arquivo build.gradle.kts do módulo app contém as configurações específicas da aplicação, como versão mínima do SDK, dependências e plugins. Veja um exemplo típico:\n// app/build.gradle.kts plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) } android { namespace = \u0026#34;com.exemplo.meuprimeiro\u0026#34; compileSdk = 35 defaultConfig { applicationId = \u0026#34;com.exemplo.meuprimeiro\u0026#34; minSdk = 24 targetSdk = 35 versionCode = 1 versionName = \u0026#34;1.0\u0026#34; } buildFeatures { compose = true } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = \u0026#34;17\u0026#34; } } dependencies { implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.ui) implementation(libs.androidx.material3) } O Version Catalog (libs.versions.toml) centraliza todas as versões de dependências em um único arquivo, facilitando a manutenção e atualização. Esse arquivo fica em gradle/libs.versions.toml e é referenciado nos scripts Gradle com libs..\nSempre que fizer alterações nos arquivos Gradle, o Android Studio exibirá uma barra no topo pedindo para sincronizar. Clique em \u0026ldquo;Sync Now\u0026rdquo; para aplicar as mudanças. É importante manter as dependências atualizadas para receber correções de segurança e novos recursos.\nConfigurando o Emulador Android Para testar sua aplicação, você pode usar um dispositivo físico ou o emulador Android. O emulador é mais conveniente para desenvolvimento do dia a dia, pois permite testar em diferentes tamanhos de tela e versões do Android sem precisar de múltiplos dispositivos.\nPara configurar o emulador, vá em \u0026ldquo;Tools \u0026gt; Device Manager\u0026rdquo; e clique em \u0026ldquo;Create Virtual Device\u0026rdquo;. Selecione um modelo de dispositivo (ex: Pixel 7) e escolha uma imagem do sistema (system image) com Google Play APIs. Recomendamos usar a imagem mais recente disponível.\nNas configurações avançadas do emulador, ajuste a quantidade de RAM dedicada e ative a aceleração por hardware (HAXM no Windows/macOS ou KVM no Linux). Isso melhora significativamente a performance do emulador.\n// Você pode verificar se está rodando no emulador com: import android.os.Build fun isEmulator(): Boolean { return Build.FINGERPRINT.startsWith(\u0026#34;generic\u0026#34;) || Build.FINGERPRINT.startsWith(\u0026#34;unknown\u0026#34;) || Build.MODEL.contains(\u0026#34;Emulator\u0026#34;) || Build.MODEL.contains(\u0026#34;Android SDK built for x86\u0026#34;) } Para conectar um dispositivo físico, ative as \u0026ldquo;Opções do Desenvolvedor\u0026rdquo; nas configurações do aparelho (toque 7 vezes em \u0026ldquo;Número da versão\u0026rdquo;) e habilite a \u0026ldquo;Depuração USB\u0026rdquo;. Conecte o dispositivo via USB e o Android Studio o reconhecerá automaticamente.\nAtalhos e Produtividade no Android Studio Dominar os atalhos do Android Studio aumenta significativamente sua produtividade. Aqui estão os mais importantes para desenvolvedores Kotlin:\nCmd/Ctrl + Shift + A: buscar qualquer ação ou configuração Cmd/Ctrl + B: ir para a declaração de uma fun ou class Cmd/Ctrl + Shift + F: buscar texto em todo o projeto Alt + Enter: mostrar sugestões e quick fixes Cmd/Ctrl + N: gerar código (constructors, getters, etc.) Shift + Shift: buscar qualquer coisa (arquivos, classes, símbolos) O Android Studio também possui suporte nativo para refatoração de código Kotlin. Use \u0026ldquo;Shift + F6\u0026rdquo; para renomear variáveis, funções e classes com segurança. O \u0026ldquo;Cmd/Ctrl + Alt + M\u0026rdquo; extrai um trecho de código selecionado para uma nova função.\nOutra funcionalidade poderosa é o Logcat, acessível na parte inferior da IDE. Ele exibe os logs da aplicação em tempo real, permitindo filtrar por tag, nível de log e processo. Use Log.d(\u0026quot;TAG\u0026quot;, \u0026quot;mensagem\u0026quot;) no seu código para adicionar logs de debug.\nDicas e Erros Comuns Gradle sync falhando: se a sincronização do Gradle falhar, verifique sua conexão com a internet. O Gradle precisa baixar dependências de repositórios remotos. Também verifique se o proxy da empresa não está bloqueando o acesso.\nEmulador lento: certifique-se de que a aceleração por hardware está habilitada. No Windows, instale o HAXM via SDK Manager. No Linux, verifique se o KVM está configurado corretamente.\nVersão do JDK incorreta: o Android Studio inclui seu próprio JDK (JetBrains Runtime). Evite configurar um JDK externo a menos que tenha um motivo específico. Isso evita problemas de compatibilidade.\nNão atualizar o Android Studio: mantenha a IDE e os plugins sempre atualizados. As atualizações incluem correções de bugs, melhorias de performance e novos recursos para Kotlin.\nIgnorar os warnings do Lint: o Android Lint analisa seu código em busca de problemas potenciais. Preste atenção aos avisos e corrija-os antes de publicar seu app.\nEsquecer de configurar o .gitignore: ao iniciar um projeto, certifique-se de que arquivos como .idea/, build/ e local.properties estejam no .gitignore para evitar problemas no controle de versão.\nConclusão e Próximos Passos Neste tutorial, você aprendeu a instalar e configurar o Android Studio para desenvolvimento com Kotlin. Cobrimos desde o download e instalação da IDE até a criação de um projeto, configuração do Gradle, setup do emulador e dicas de produtividade.\nCom o ambiente configurado, você está pronto para começar a desenvolver aplicações Android com Kotlin. O Android Studio é uma ferramenta poderosa que, quando bem configurada, torna o desenvolvimento muito mais produtivo e agradável.\nPara continuar sua jornada, recomendamos os seguintes tutoriais:\nPrimeiro App Android com Kotlin para criar sua primeira aplicação completa Jetpack Compose: Introdução para aprender UI declarativa moderna Boas Práticas e Code Style para escrever código Kotlin idiomático desde o início ","permalink":"https://kotlin.dev.br/tutoriais/kotlin-android-studio/","summary":"\u003cp\u003eConfigurar o ambiente de desenvolvimento é o primeiro passo para começar a programar em Kotlin para Android. Neste tutorial, vamos guiá-lo por todo o processo de instalação e configuração do Android Studio, desde o download até a criação do seu primeiro projeto. Se você é iniciante ou está migrando de outra linguagem, este guia completo vai ajudá-lo a começar com o pé direito.\u003c/p\u003e\n\u003ch2 id=\"pré-requisitos-e-download-do-android-studio\"\u003ePré-requisitos e Download do Android Studio\u003c/h2\u003e\n\u003cp\u003eAntes de começar, verifique se seu computador atende aos requisitos mínimos para rodar o Android Studio. Você precisará de pelo menos 8 GB de RAM (16 GB recomendado), 8 GB de espaço em disco disponível é um processador moderno com suporte a virtualização para o emulador Android.\u003c/p\u003e","title":"Configurando Kotlin no Android Studio Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Neste tutorial, vamos explorar os conceitos avançados de Coroutines em Kotlin, com foco em Flow e Channel. Essas duas ferramentas são essenciais para lidar com fluxos de dados assíncronos de forma eficiente e elegante. Se você já domina o básico de coroutines, este é o próximo passo para elevar seu nível como desenvolvedor Kotlin.\nO que são Flows em Kotlin? O Flow é um tipo de stream assíncrono e frio (cold stream) que emite valores sequencialmente. Diferente de um Channel, o Flow só começa a produzir valores quando alguém os coleta. Isso o torna ideal para cenários em que você precisa processar uma sequência de dados de forma reativa.\nUm Flow é declarado usando o builder flow {}, e cada valor é emitido com a função suspend emit(). O coletor recebe os valores usando collect {}.\nimport kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking fun numerosSimples(): Flow\u0026lt;Int\u0026gt; = flow { for (i in 1..5) { kotlinx.coroutines.delay(300) emit(i) } } fun main() = runBlocking { numerosSimples().collect { valor -\u0026gt; println(\u0026#34;Recebido: $valor\u0026#34;) } } Neste exemplo, o Flow emite os números de 1 a 5, com um atraso de 300 milissegundos entre cada emissão. O collect é uma função terminal que consome os valores emitidos. Note que o Flow respeita a structured concurrency do Kotlin, ou seja, ele é cancelado automaticamente quando o escopo da coroutine é cancelado.\nOs Flows são cold streams, o que significa que o código dentro do builder flow {} só é executado quando alguém chama collect. Isso é diferente de Channels, que são hot streams e podem produzir valores independentemente de haver um consumidor.\nOperadores de Flow Uma das maiores vantagens do Flow é a rica coleção de operadores intermediários disponíveis. Eles permitem transformar, filtrar e combinar fluxos de dados de maneira declarativa, semelhante ao que fazemos com Collections.\nimport kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking fun main() = runBlocking { val fluxo = (1..20).asFlow() fluxo .filter { it % 2 == 0 } .map { it * it } .take(5) .collect { valor -\u0026gt; println(\u0026#34;Valor transformado: $valor\u0026#34;) } } Alguns dos operadores mais utilizados são:\nmap: transforma cada valor emitido pelo Flow. filter: filtra valores com base em uma condição. take: limita a quantidade de valores emitidos. zip: combina dois Flows em pares. flatMapConcat: transforma cada valor em um novo Flow e os concatena. onEach: executa uma ação para cada valor sem alterá-lo. catch: intercepta exceções lançadas upstream. flowOn: altera o dispatcher em que o Flow é executado. O operador flowOn é particularmente importante, pois permite que você mude o contexto de execução do Flow sem afetar o coletor. Por exemplo, você pode processar dados em Dispatchers.IO e coletar na thread principal.\nimport kotlinx.coroutines.flow.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking fun buscarDados(): Flow\u0026lt;String\u0026gt; = flow { emit(\u0026#34;Dado 1\u0026#34;) emit(\u0026#34;Dado 2\u0026#34;) emit(\u0026#34;Dado 3\u0026#34;) }.flowOn(Dispatchers.IO) fun main() = runBlocking { buscarDados() .catch { e -\u0026gt; println(\u0026#34;Erro capturado: ${e.message}\u0026#34;) } .collect { dado -\u0026gt; println(\u0026#34;Coletado na Main: $dado\u0026#34;) } } Channels: Comunicação entre Coroutines Enquanto o Flow é um cold stream, o Channel é um hot stream que permite a comunicação entre coroutines. Pense em um Channel como uma fila (queue) thread-safe que conecta produtores e consumidores de dados.\nChannels são úteis quando você precisa de comunicação bidirecional entre coroutines ou quando deseja que o produtor funcione independentemente do consumidor. Existem diferentes tipos de Channel:\nChannel.RENDEZVOUS (padrão): sem buffer, o produtor espera o consumidor estar pronto. Channel.BUFFERED: com buffer limitado (64 por padrão). Channel.UNLIMITED: buffer ilimitado, nunca suspende o produtor. Channel.CONFLATED: mantém apenas o último valor enviado. import kotlinx.coroutines.* import kotlinx.coroutines.channels.* fun main() = runBlocking { val channel = Channel\u0026lt;Int\u0026gt;(capacity = Channel.BUFFERED) launch { for (i in 1..10) { println(\u0026#34;Enviando: $i\u0026#34;) channel.send(i) delay(100) } channel.close() } launch { for (valor in channel) { println(\u0026#34;Recebendo: $valor\u0026#34;) delay(250) } } } Neste exemplo, o produtor envia valores mais rápido do que o consumidor processa. Graças ao buffer, o produtor pode adiantar o envio de alguns valores sem precisar aguardar o consumidor. Quando o buffer está cheio, o produtor é suspenso automaticamente até que haja espaço.\nÉ fundamental lembrar de fechar o Channel com close() quando não há mais dados a enviar. Caso contrário, o consumidor ficará suspenso indefinidamente esperando novos valores.\nStateFlow e SharedFlow O Kotlin também oferece dois tipos especiais de Flow para cenários de estado e eventos:\nStateFlow é um Flow que mantém um único valor atual e emite atualizações para todos os coletores. Ele é ideal para representar estado em aplicações Android com Jetpack Compose ou ViewModels.\nSharedFlow é mais flexível e permite configurar replay (quantidade de valores emitidos novamente para novos coletores) e buffer. Ele é perfeito para eventos que não devem ser perdidos.\nimport kotlinx.coroutines.* import kotlinx.coroutines.flow.* class ContadorViewModel { private val _contador = MutableStateFlow(0) val contador: StateFlow\u0026lt;Int\u0026gt; = _contador.asStateFlow() fun incrementar() { _contador.value++ } fun decrementar() { _contador.value-- } } fun main() = runBlocking { val viewModel = ContadorViewModel() val job = launch { viewModel.contador.collect { valor -\u0026gt; println(\u0026#34;Contador: $valor\u0026#34;) } } viewModel.incrementar() delay(100) viewModel.incrementar() delay(100) viewModel.decrementar() delay(100) job.cancel() } A diferença principal entre StateFlow e SharedFlow é que StateFlow sempre possui um valor inicial e utiliza distinctUntilChanged por padrão, ou seja, só emite quando o valor realmente muda. SharedFlow não tem valor inicial e pode emitir valores repetidos.\nDicas e Erros Comuns Não coletar Flow na Main Thread sem cuidado: em aplicações Android, sempre colete Flows no escopo correto (viewModelScope, lifecycleScope) para evitar memory leaks.\nEsquecer de fechar Channels: um Channel não fechado pode causar coroutines suspensas para sempre. Sempre use close() ou considere usar produce {} que fecha automaticamente.\nUsar Channel quando Flow basta: se você não precisa de comunicação bidirecional ou hot stream, prefira Flow. Ele é mais simples, seguro e compõe melhor com operadores.\nIgnorar o operador catch: sem tratamento de erros, exceções em Flows podem derrubar sua aplicação. Sempre adicione catch {} antes de collect {}.\nConfundir flowOn com launchIn: o flowOn muda o contexto de execução do upstream, enquanto launchIn define o escopo para o coletor. Usar ambos incorretamente pode levar a bugs sutis.\nNão usar stateIn ou shareIn em ViewModels: converter um cold Flow em StateFlow ou SharedFlow com stateIn ou shareIn evita múltiplas execuções desnecessárias quando há vários coletores.\nConclusão e Próximos Passos Neste tutorial, exploramos os conceitos avançados de Coroutines em Kotlin, incluindo Flow, Channel, StateFlow e SharedFlow. Essas ferramentas formam a base da programação assíncrona moderna em Kotlin e são fundamentais para qualquer desenvolvedor que trabalhe com aplicações reativas.\nDominar Flows e Channels permite criar aplicações mais responsivas, com melhor gerenciamento de recursos e código mais limpo. A chave é entender quando usar cada ferramenta: Flow para streams frios e reativos, Channel para comunicação entre coroutines, StateFlow para estado observável e SharedFlow para eventos.\nPara continuar sua jornada de aprendizado, recomendamos os seguintes tutoriais:\nPrimeiro App Android com Kotlin para aplicar coroutines em um projeto real Jetpack Compose: Introdução para usar StateFlow com UI declarativa Testes Unitários com Kotlin para aprender a testar código assíncrono Criando API REST com Ktor para usar Flow em aplicações server-side Se você quer comparar modelos de concorrência, Go utiliza goroutines com um modelo de concorrência elegante e Rust oferece async/await com garantias de segurança em tempo de compilação.\n","permalink":"https://kotlin.dev.br/tutoriais/coroutines-avancado/","summary":"\u003cp\u003eNeste tutorial, vamos explorar os conceitos avançados de \u003ca href=\"/glossario/coroutine/\"\u003eCoroutines\u003c/a\u003e em Kotlin, com foco em \u003ca href=\"/glossario/flow/\"\u003eFlow\u003c/a\u003e e \u003ca href=\"/glossario/channel/\"\u003eChannel\u003c/a\u003e. Essas duas ferramentas são essenciais para lidar com fluxos de dados assíncronos de forma eficiente e elegante. Se você já domina o básico de coroutines, este é o próximo passo para elevar seu nível como desenvolvedor Kotlin.\u003c/p\u003e\n\u003ch2 id=\"o-que-são-flows-em-kotlin\"\u003eO que são Flows em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO \u003ca href=\"/glossario/flow/\"\u003eFlow\u003c/a\u003e é um tipo de stream assíncrono e frio (cold stream) que emite valores sequencialmente. Diferente de um \u003ca href=\"/glossario/channel/\"\u003eChannel\u003c/a\u003e, o Flow só começa a produzir valores quando alguém os coleta. Isso o torna ideal para cenários em que você precisa processar uma sequência de dados de forma reativa.\u003c/p\u003e","title":"Coroutines Avançadas: Flow e Channel Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Aplicativos desktop com Kotlin: como criar? Sim, e possível criar aplicativos desktop completos e profissionais usando Kotlin. A principal opção em 2026 é o Compose for Desktop, parte do projeto Compose Multiplatform da JetBrains, que permite usar a mesma API declarativa do Jetpack Compose para construir interfaces desktop nativas. Mas existem outras opções também. Vamos explorar tudo em detalhes.\nCompose for Desktop: a principal opção Compose for Desktop é a forma mais moderna e recomendada de criar aplicativos desktop com Kotlin. Ele usa a mesma API declarativa que o Jetpack Compose para Android, o que significa que se você já conhece Compose, a transicao e praticamente instantanea.\nimport androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.layout.* import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Window import androidx.compose.ui.window.application fun main() = application { Window( onCloseRequest = ::exitApplication, title = \u0026#34;Gerenciador de Tarefas\u0026#34; ) { MaterialTheme { AppPrincipal() } } } @Composable fun AppPrincipal() { var tarefas by remember { mutableStateOf(listOf\u0026lt;String\u0026gt;()) } var novaTarefa by remember { mutableStateOf(\u0026#34;\u0026#34;) } Column( modifier = Modifier .fillMaxSize() .padding(24.dp) ) { Text( text = \u0026#34;Minhas Tarefas\u0026#34;, style = MaterialTheme.typography.headlineMedium ) Spacer(modifier = Modifier.height(16.dp)) Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { OutlinedTextField( value = novaTarefa, onValueChange = { novaTarefa = it }, label = { Text(\u0026#34;Nova tarefa\u0026#34;) }, modifier = Modifier.weight(1f) ) Spacer(modifier = Modifier.width(8.dp)) Button( onClick = { if (novaTarefa.isNotBlank()) { tarefas = tarefas + novaTarefa novaTarefa = \u0026#34;\u0026#34; } } ) { Text(\u0026#34;Adicionar\u0026#34;) } } Spacer(modifier = Modifier.height(16.dp)) tarefas.forEachIndexed { indice, tarefa -\u0026gt; Card( modifier = Modifier .fillMaxWidth() .padding(vertical = 4.dp) ) { Row( modifier = Modifier .fillMaxWidth() .padding(16.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { Text(text = tarefa) IconButton(onClick = { tarefas = tarefas.filterIndexed { i, _ -\u0026gt; i != indice } }) { Text(\u0026#34;X\u0026#34;) } } } } if (tarefas.isEmpty()) { Box( modifier = Modifier.fillMaxWidth().padding(32.dp), contentAlignment = Alignment.Center ) { Text( text = \u0026#34;Nenhuma tarefa cadastrada\u0026#34;, color = MaterialTheme.colorScheme.outline ) } } } } Como começar com Compose for Desktop Configuração do projeto:\nA forma mais fácil de começar e usando o assistente do IntelliJ IDEA ou o Kotlin Multiplatform Wizard.\nO arquivo build.gradle.kts tipico para um projeto Compose Desktop:\nplugins { kotlin(\u0026#34;jvm\u0026#34;) id(\u0026#34;org.jetbrains.compose\u0026#34;) } dependencies { implementation(compose.desktop.currentOs) implementation(compose.material3) } compose.desktop { application { mainClass = \u0026#34;MainKt\u0026#34; } } Funcionalidades avançadas do Compose Desktop Menus e barras de ferramentas:\nimport androidx.compose.ui.window.* fun main() = application { Window( onCloseRequest = ::exitApplication, title = \u0026#34;Editor de Texto\u0026#34;, state = rememberWindowState(width = 800.dp, height = 600.dp) ) { MenuBar { Menu(\u0026#34;Arquivo\u0026#34;) { Item(\u0026#34;Novo\u0026#34;, onClick = { /* novo arquivo */ }) Item(\u0026#34;Abrir\u0026#34;, onClick = { /* abrir arquivo */ }) Item(\u0026#34;Salvar\u0026#34;, onClick = { /* salvar arquivo */ }) Separator() Item(\u0026#34;Sair\u0026#34;, onClick = ::exitApplication) } Menu(\u0026#34;Editar\u0026#34;) { Item(\u0026#34;Copiar\u0026#34;, onClick = { /* copiar */ }) Item(\u0026#34;Colar\u0026#34;, onClick = { /* colar */ }) } Menu(\u0026#34;Ajuda\u0026#34;) { Item(\u0026#34;Sobre\u0026#34;, onClick = { /* mostrar sobre */ }) } } MaterialTheme { EditorConteudo() } } } System Tray (icone na bandeja do sistema):\nfun main() = application { Tray( icon = painterResource(\u0026#34;icone.png\u0026#34;), menu = { Item(\u0026#34;Abrir\u0026#34;, onClick = { /* abrir janela */ }) Item(\u0026#34;Sair\u0026#34;, onClick = ::exitApplication) } ) Window(onCloseRequest = ::exitApplication, title = \u0026#34;Meu App\u0026#34;) { MaterialTheme { Text(\u0026#34;Aplicativo com System Tray\u0026#34;) } } } Acesso ao sistema de arquivos:\nimport java.io.File import javax.swing.JFileChooser @Composable fun SeletorDeArquivos(aoSelecionarArquivo: (File) -\u0026gt; Unit) { Button(onClick = { val seletor = JFileChooser() val resultado = seletor.showOpenDialog(null) if (resultado == JFileChooser.APPROVE_OPTION) { aoSelecionarArquivo(seletor.selectedFile) } }) { Text(\u0026#34;Selecionar arquivo\u0026#34;) } } Outras opções para desktop com Kotlin TornadoFX (baseado em JavaFX)\nTornadoFX e um framework Kotlin construido sobre JavaFX. Embora seja mais antigo que Compose Desktop, ainda e usado em projetos existentes.\nSwing com Kotlin\nJava Swing funciona perfeitamente com Kotlin. E uma opção válida para projetos que precisam de compatibilidade com sistemas mais antigos, embora a API seja imperative e menos moderna.\nKotlin/Native\nPara aplicações desktop que precisam de performance maxima e acesso direto ao sistema operacional, Kotlin/Native compila para binarios nativos sem dependência da JVM.\nComparação de opções desktop Caracteristica Compose Desktop TornadoFX Swing Kotlin/Native Paradigma Declarativo Misto Imperativo Nativo Modernidade Muito moderno Moderno Datado Moderno Curva aprendizado Moderada Moderada Baixa Alta Performance Muito boa Boa Boa Excelente Comunidade Crescente Pequena Grande Pequena Futuro Promissor Estagnado manutenção Em evolução Pros e contras de apps desktop com Kotlin Vantagens:\nCompose Desktop permite compartilhar UI entre desktop, Android e iOS Acesso a todo ecossistema de bibliotecas JVM Kotlin idiomatico: null safety, coroutines, extensoes Uma única linguagem para mobile e desktop Distribuição multiplataforma (Windows, macOS, Linux) IntelliJ IDEA e o próprio melhor exemplo de app desktop em Kotlin/JVM Desvantagens:\nCompose Desktop ainda e menos maduro que frameworks nativos de cada sistema Apps JVM consomem mais memória que apps nativos puros O ecossistema de componentes prontos e menor que em web Distribuição de apps JVM requer empacotamento do runtime (JPackage ou similar) Menos vagas de emprego específicas para desktop comparado com web e mobile Tipos de aplicativos desktop ideais para Kotlin Kotlin e especialmente adequado para:\nFerramentas de produtividade e utilitarios Aplicativos empresariais internos Editores e IDEs (a JetBrains comprova isso) Dashboards e aplicativos de monitoramento Aplicativos que precisam funcionar offline Extensoes de ferramentas de desenvolvimento Distribuição de apps desktop Para distribuir seu app Kotlin desktop, você pode usar:\nJPackage: ferramenta oficial do JDK que cria instaladores nativos (.msi para Windows, .dmg para macOS, .deb/.rpm para Linux).\nCompose Gradle Plugin: o plugin do Compose já inclui tarefas de empacotamento que geram executaveis nativos para cada plataforma.\n// No build.gradle.kts compose.desktop { application { mainClass = \u0026#34;MainKt\u0026#34; nativeDistributions { targetFormats( TargetFormat.Dmg, // macOS TargetFormat.Msi, // Windows TargetFormat.Deb // Linux ) packageName = \u0026#34;MeuApp\u0026#34; packageVersion = \u0026#34;1.0.0\u0026#34; } } } Projeto prático: conversor de arquivos Para quem quer começar, um projeto excelente e criar um conversor de arquivos com interface grafica. Ele envolve:\nInterface com Compose Desktop manipulação de arquivos do sistema Processamento em background com coroutines Barra de progresso e feedback visual O futuro do Kotlin Desktop O Compose Multiplatform continua evoluindo rapidamente. A JetBrains investe pesado nessa tecnologia porque e a base do seu próprio ecossistema de IDEs futuro. Isso garante que Compose Desktop tera suporte e melhorias por muito tempo.\nA tendencia e que cada vez mais aplicativos desktop sejam construidos com Kotlin, especialmente aqueles que também precisam de versões mobile. A convergencia entre desktop e mobile através do Compose Multiplatform e um dos desenvolvimentos mais empolgantes no ecossistema Kotlin.\nPerguntas relacionadas Kotlin pode ser usado para iOS? Kotlin para desenvolvimento web Melhor IDE para Kotlin O que é Kotlin Multiplatform? Kotlin vale a pena em 2026? ","permalink":"https://kotlin.dev.br/perguntas/kotlin-desktop-apps/","summary":"\u003ch2 id=\"aplicativos-desktop-com-kotlin-como-criar\"\u003eAplicativos desktop com Kotlin: como criar?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eSim, e possível criar aplicativos desktop completos e profissionais usando Kotlin.\u003c/strong\u003e A principal opção em 2026 é o \u003cstrong\u003eCompose for Desktop\u003c/strong\u003e, parte do projeto Compose Multiplatform da JetBrains, que permite usar a mesma API declarativa do Jetpack Compose para construir interfaces desktop nativas. Mas existem outras opções também. Vamos explorar tudo em detalhes.\u003c/p\u003e\n\u003ch3 id=\"compose-for-desktop-a-principal-opção\"\u003eCompose for Desktop: a principal opção\u003c/h3\u003e\n\u003cp\u003eCompose for Desktop é a forma mais moderna e recomendada de criar aplicativos desktop com Kotlin. Ele usa a mesma API declarativa que o Jetpack Compose para Android, o que significa que se você já conhece Compose, a transicao e praticamente instantanea.\u003c/p\u003e","title":"Aplicativos Desktop com Kotlin: Como Criar? | Kotlin Brasil"},{"content":"Certificação Google em Kotlin: vale a pena? A certificação Google Associate Android Developer é a credencial mais reconhecida para desenvolvedores Android que trabalham com Kotlin. Se você esta considerando obte-la, este guia cobre tudo que você precisa saber: como funciona, o que é cobrado, como se preparar e se realmente faz diferenca na carreira.\nO que é a certificação Google Associate Android Developer? A certificação Google Associate Android Developer é um exame prático que válida suas habilidades em desenvolvimento Android com Kotlin. Diferente de certificacoes teoricas que cobram apenas conhecimento conceitual, essa certificação exige que você escreva código real em um projeto Android.\nO exame consiste em:\nProva prática: você recebe um projeto Android e precisa implementar funcionalidades específicas dentro de um prazo determinado Entrevista de saida: apos a prova prática, há uma entrevista por video onde você explica suas decisoes tecnicas Conteudo cobrado na certificação O exame cobre os principais pilares do desenvolvimento Android moderno com Kotlin:\nInterface do usuário (UI)\n// Você precisa dominar Jetpack Compose @Composable fun TelaDeDetalhes(produto: Produto, aoClicarComprar: () -\u0026gt; Unit) { Scaffold( topBar = { TopAppBar(title = { Text(produto.nome) }) } ) { padding -\u0026gt; Column( modifier = Modifier .fillMaxSize() .padding(padding) .padding(16.dp) ) { Text( text = produto.descricao, style = MaterialTheme.typography.bodyLarge ) Spacer(modifier = Modifier.height(16.dp)) Text( text = \u0026#34;R$ ${\u0026#34;%.2f\u0026#34;.format(produto.preco)}\u0026#34;, style = MaterialTheme.typography.headlineMedium, color = MaterialTheme.colorScheme.primary ) Spacer(modifier = Modifier.weight(1f)) Button( onClick = aoClicarComprar, modifier = Modifier.fillMaxWidth() ) { Text(\u0026#34;Comprar\u0026#34;) } } } } Gerenciamento de dados\n// Room Database - persistencia local @Entity(tableName = \u0026#34;tarefas\u0026#34;) data class TarefaEntity( @PrimaryKey(autoGenerate = true) val id: Long = 0, val titulo: String, val descricao: String, val concluida: Boolean = false, val criadaEm: Long = System.currentTimeMillis() ) @Dao interface TarefaDao { @Query(\u0026#34;SELECT * FROM tarefas ORDER BY criadaEm DESC\u0026#34;) fun obterTodas(): Flow\u0026lt;List\u0026lt;TarefaEntity\u0026gt;\u0026gt; @Query(\u0026#34;SELECT * FROM tarefas WHERE concluida = 0\u0026#34;) fun obterPendentes(): Flow\u0026lt;List\u0026lt;TarefaEntity\u0026gt;\u0026gt; @Insert suspend fun inserir(tarefa: TarefaEntity) @Update suspend fun atualizar(tarefa: TarefaEntity) @Delete suspend fun remover(tarefa: TarefaEntity) } @Database(entities = [TarefaEntity::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun tarefaDao(): TarefaDao } Arquitetura é ViewModel\n// ViewModel com StateFlow class TarefaViewModel(private val repositorio: TarefaRepositorio) : ViewModel() { private val _uiState = MutableStateFlow(TarefaUiState()) val uiState: StateFlow\u0026lt;TarefaUiState\u0026gt; = _uiState.asStateFlow() init { carregarTarefas() } private fun carregarTarefas() { viewModelScope.launch { repositorio.obterTodas().collect { tarefas -\u0026gt; _uiState.update { estado -\u0026gt; estado.copy( tarefas = tarefas, carregando = false ) } } } } fun adicionarTarefa(titulo: String, descricao: String) { viewModelScope.launch { repositorio.inserir( TarefaEntity(titulo = titulo, descricao = descricao) ) } } fun alternarConclusao(tarefa: TarefaEntity) { viewModelScope.launch { repositorio.atualizar(tarefa.copy(concluida = !tarefa.concluida)) } } } data class TarefaUiState( val tarefas: List\u0026lt;TarefaEntity\u0026gt; = emptyList(), val carregando: Boolean = true, val erro: String? = null ) Outros topicos cobrados:\nNavegação entre telas WorkManager para tarefas em background Notificacoes Testes unitarios e instrumentados Permissoes e ciclo de vida Acessibilidade Como se preparar 1. Domine os fundamentos do Kotlin\nAntes de pensar na certificação, certifique-se de que você esta confortavel com a linguagem Kotlin: null safety, coroutines, funções de extensao, sealed classes e coleções.\n2. Estude o Android Developer Fundamentals\nO Google oferece cursos gratuitos que cobrem exatamente o conteudo da certificação. Os codelabs oficiais são especialmente úteis porque são práticos e focados.\n3. Construa projetos completos\nA certificação e prática, entao você precisa estar acostumado a construir apps do zero. Crie pelo menos 3 a 5 projetos que usem:\nJetpack Compose para UI Room para persistencia ViewModel e StateFlow para gerenciamento de estado WorkManager para sincronização e tarefas adiadas Navegação entre telas Chamadas a APIs externas 4. Pratique testes\nTestes são uma parte importante da certificação. Pratique escrever testes unitarios com JUnit e MockK, e testes de UI com Compose Testing.\n5. Simule o ambiente do exame\nTente resolver desafios com tempo limitado para se acostumar com a pressao. Pegue um projeto incompleto e tente implementar funcionalidades em um prazo determinado.\nQuanto custa e como se inscrever O valor da certificação pode variar, mas geralmente esta na faixa de USD 149. O pagamento e feito diretamente no site do Google. Apos o pagamento, você recebe acesso ao exame e tem um prazo para completa-lo.\nO exame pode ser feito remotamente, de qualquer lugar com uma conexao estavel de internet. Você precisa de uma webcam e um ambiente tranquilo durante a prova.\nPros e contras da certificação Vantagens:\nReconhecimento internacional do Google Diferencial no curriculo, especialmente para vagas Android Processo prático que realmente válida habilidades reais Forca você a estudar e dominar topicos que talvez estivesse evitando Aumenta a confianca profissional Pode justificar pedidos de aumento ou promocao Desvantagens:\nCusto pode ser significativo para alguns A certificação sozinha não substitui experiência prática Precisa de renovacao periodica Algumas empresas não consideram certificacoes no processo seletivo O conteudo pode ficar desatualizado entre versões do exame Vale a pena para a carreira? A resposta depende do seu contexto:\nVale muito a pena se você:\nEsta comecando na carreira e precisa de credibilidade Quer se destacar em processos seletivos competitivos Trabalha em empresas que valorizam certificacoes Busca válidação formal das suas habilidades Quer um objetivo concreto para direcionar seus estudos Pode não ser prioridade se você:\nJa tem anos de experiência comprovada com Android Tem um portfolio robusto de projetos no GitHub Trabalha em empresas que priorizam habilidades práticas sobre certificacoes Prefere investir o valor em cursos ou conferencias Alternativas e complementos Alem da certificação Google, considere:\nCertificacoes da JetBrains: focadas especificamente em Kotlin Portfolio no GitHub: projetos reais demonstram habilidade de forma tangivel Contribuicoes open source: mostram capacidade de trabalhar em equipe e com código real Blog técnico: demonstra conhecimento aprofundado e capacidade de comunicação Dicas finais A certificação e uma ferramenta poderosa, mas não e a única coisa que importa. O ideal e combina-la com experiência prática, portfolio e participacao na comunidade. Juntos, esses elementos constroem um perfil profissional completo e atraente para recrutadores.\nSe você decidir fazer a certificação, dedique pelo menos 2 a 3 meses de preparacao focada. Nao tente fazer o exame sem preparacao adequada, pois o formato prático não perdoa falta de experiência.\nPerguntas relacionadas E fácil encontrar emprego com Kotlin? Kotlin vale a pena em 2026? Como aprender Kotlin em 2026? Comunidade Kotlin no Brasil Salário de desenvolvedor Kotlin ","permalink":"https://kotlin.dev.br/perguntas/kotlin-certificacao-google/","summary":"\u003ch2 id=\"certificação-google-em-kotlin-vale-a-pena\"\u003eCertificação Google em Kotlin: vale a pena?\u003c/h2\u003e\n\u003cp\u003eA certificação \u003cstrong\u003eGoogle Associate Android Developer\u003c/strong\u003e é a credencial mais reconhecida para desenvolvedores Android que trabalham com Kotlin. Se você esta considerando obte-la, este guia cobre tudo que você precisa saber: como funciona, o que é cobrado, como se preparar e se realmente faz diferenca na carreira.\u003c/p\u003e\n\u003ch3 id=\"o-que-é-a-certificação-google-associate-android-developer\"\u003eO que é a certificação Google Associate Android Developer?\u003c/h3\u003e\n\u003cp\u003eA certificação Google Associate Android Developer é um exame prático que válida suas habilidades em desenvolvimento Android com Kotlin. Diferente de certificacoes teoricas que cobram apenas conhecimento conceitual, essa certificação exige que você \u003cstrong\u003eescreva código real\u003c/strong\u003e em um projeto Android.\u003c/p\u003e","title":"Certificação Google em Kotlin: Vale a Pena? | Kotlin Brasil"},{"content":"Comunidade Kotlin no Brasil: como participar? A comunidade Kotlin no Brasil e vibrante, acolhedora e em pleno crescimento. Diferente de algumas comunidades de tecnologia que podem ser intimidadoras para iniciantes, a comunidade Kotlin brasileira se destaca pela receptividade e pela vontade de ajudar quem esta comecando. Neste guia, vou mostrar todos os caminhos para você se conectar e participar ativamente.\nPor que participar de uma comunidade? Antes de listar onde encontrar a comunidade, vale entender por que participar e tao importante para sua carreira:\nNetworking: muitas vagas de emprego são preenchidas por indicacao. Conhecer pessoas da area multiplica suas oportunidades. Aprendizado acelerado: duvidas que você levaria horas pesquisando podem ser resolvidas em minutos com a ajuda de alguem mais experiente. Motivacao: ver outras pessoas evoluindo inspira você a continuar estudando. Visibilidade profissional: participar ativamente de comunidades te torna conhecido no mercado. Contribuicao: ajudar outros consolida seu próprio conhecimento e cria uma rede de reciprocidade. Grupos e canais online Telegram\nO Telegram é um dos principais canais da comunidade Kotlin brasileira. Existem grupos ativos onde desenvolvedores de todos os niveis trocam experiencias, tiram duvidas e compartilham novidades.\nOs grupos costumam ter regras claras de convivencia e moderadores dedicados, o que mantém a qualidade das discussoes. Tanto iniciantes quanto seniors participam, criando um ambiente diverso e enriquecedor.\nDiscord\nServidores de Discord voltados para desenvolvimento Android e Kotlin em português tem ganhado popularidade. A vantagem do Discord é a organizacao por canais tematicos, o qué fácilita encontrar discussoes específicas sobre o assunto que te interessa.\nStack Overflow em Português\nO Stack Overflow em português tem uma seção ativa de perguntas sobre Kotlin. E um otimo lugar para buscar respostas e também para contribuir respondendo duvidas de outros desenvolvedores.\nGitHub\nAcompanhar e contribuir em repositórios brasileiros de Kotlin no GitHub é uma forma poderosa de participar da comunidade. Alem de aprender com código real, você constroi seu portfolio e se conecta com mantenedores de projetos.\nEventos presenciais e online Meetups locais\nVarias cidades brasileiras tem meetups regulares de Kotlin e Android. São Paulo, Rio de Janeiro, Belo Horizonte, Curitiba, Porto Alegre, Florianopolis e Brasilia costumam ter encontros mensais ou bimestrais.\nOs meetups geralmente incluem:\nPalestras tecnicas de 30 a 45 minutos Lightning talks de 10 a 15 minutos Networking com comes e bebes Sessoes de perguntas e respostas Conferencias\nO Brasil tem algumas conferencias relevantes para desenvolvedores Kotlin:\nKotlinConf: conferencia oficial da JetBrains, com transmissao online acessivel do Brasil Android Makers: evento focado em Android com muito conteudo Kotlin The Developers Conference (TDC): uma das maiores conferencias de tecnologia do Brasil, com trilhas de Kotlin e Android DevFest: eventos regionais organizados por GDGs (Google Developer Groups) com conteudo de Kotlin Eventos online\nA pandemia acelerou a adoção de eventos online, é muitos deles continuam acontecendo nesse formato. Lives, webinars e workshops online são frequentes e acessiveis de qualquer lugar do Brasil.\nGoogle Developer Groups (GDGs) Os GDGs são comunidades locais apoiadas pelo Google que organizam eventos, workshops e hackathons. Como Kotlin é a linguagem oficial do Android, os GDGs brasileiros frequentemente promovem atividades relacionadas a Kotlin.\nExistem GDGs em diversas cidades brasileiras, e participar e gratuito. Procure o GDG da sua cidade ou região para ficar por dentro dos próximos eventos.\nComo começar a contribuir Participar de uma comunidade não e só consumir conteudo. A contribuicao ativa traz beneficios enormes:\nResponda perguntas\nMesmo como iniciante, você pode ajudar quem esta um passo atras de você. Responder duvidas consolida seu conhecimento e te torna visivel na comunidade.\nEscreva conteudo\nArtigos, tutoriais e posts em blogs sobre suas experiencias com Kotlin são extremamente valiosos para a comunidade. O conteudo em português e especialmente importante, já que muitos desenvolvedores brasileiros preferem estudar em sua lingua nativa.\n// Compartilhar snippets uteis e uma forma simples de contribuir // Exemplo: funcoes de extensao que todo projeto Kotlin pode usar fun String.capitalizar(): String = this.lowercase().replaceFirstChar { it.uppercase() } fun \u0026lt;T\u0026gt; List\u0026lt;T\u0026gt;.segundoOuNull(): T? = if (this.size \u0026gt;= 2) this[1] else null fun Long.formatarComoMoeda(): String = \u0026#34;R$ ${\u0026#34;%.2f\u0026#34;.format(this / 100.0)}\u0026#34; fun Int.estaEntre(min: Int, max: Int): Boolean = this in min..max // Uso pratico fun main() { println(\u0026#34;kotlin brasil\u0026#34;.capitalizar()) // \u0026#34;Kotlin brasil\u0026#34; println(listOf(\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;).segundoOuNull()) // \u0026#34;b\u0026#34; println(15990L.formatarComoMoeda()) // \u0026#34;R$ 159,90\u0026#34; println(25.estaEntre(18, 65)) // true } Participe de hackatons\nHackathons são eventos onde equipes criam projetos em um curto periodo de tempo. São otimos para praticar, conhecer pessoas e testar ideias. Muitos hackathons brasileiros aceitam projetos em Kotlin.\nFaca palestras\nNao precisa ser expert para palestrar. Compartilhar sua jornada de aprendizado, um projeto que você criou ou um problema que resolveu já e conteudo valioso. Comece com lightning talks de 5 a 10 minutos em meetups locais.\nMentoria A comunidade Kotlin brasileira tem um espirito forte de mentoria. Desenvolvedores mais experientes frequentemente se disponibilizam para orientar iniciantes. Algumas formas de encontrar mentores:\nParticipe ativamente de grupos e demonstre interesse genuino Peca feedback sobre seu código de forma respeitosa Ofereca ajuda em troca (não precisa ser técnica) Seja consistente na sua participacao Conteudo brasileiro sobre Kotlin A producao de conteudo em português sobre Kotlin tem crescido significativamente. Você pode encontrar:\nCanais no YouTube: vários criadores de conteudo brasileiros produzem series e tutoriais sobre Kotlin Blogs e sites: incluindo este que você esta lendo agora Podcasts: alguns podcasts brasileiros de tecnologia cobrem Kotlin regularmente Newsletters: boletins semanais com novidades do ecossistema Kotlin Pros e contras de diferentes formas de participacao Grupos online (Telegram, Discord):\nPro: acesso imediato, disponivel 24h Pro: fácil de participar de qualquer lugar Contra: discussoes podem ser superficiais Contra: volume de mensagens pode ser alto Meetups presenciais:\nPro: networking mais profundo e pessoal Pro: palestras tecnicas de qualidade Contra: limitado a quem mora perto Contra: frequência geralmente mensal Conferencias:\nPro: conteudo de alto nível Pro: oportunidade de conhecer referências da area Contra: algumas são pagas Contra: acontecem poucas vezes ao ano Contribuicao open source:\nPro: aprendizado prático com código real Pro: visibilidade internacional Contra: curva de aprendizado inicial Contra: pode ser intimidador para iniciantes Dicas finais A comunidade Kotlin no Brasil e um dos maiores ativos que você pode aproveitar na sua carreira. Nao tenha vergonha de ser iniciante, não espere estar \u0026ldquo;pronto\u0026rdquo; para participar, e não subestime o poder do networking. As melhores oportunidades profissionais frequentemente surgem de conexoes feitas em comunidades de tecnologia.\nComece hoje: entre em um grupo, apresente-se e faça uma pergunta. Você vai se surpreender com a receptividade.\nPerguntas relacionadas Kotlin vale a pena em 2026? Como aprender Kotlin em 2026? E fácil encontrar emprego com Kotlin? Como praticar Kotlin? Certificação Google em Kotlin ","permalink":"https://kotlin.dev.br/perguntas/kotlin-comunidade-brasil/","summary":"\u003ch2 id=\"comunidade-kotlin-no-brasil-como-participar\"\u003eComunidade Kotlin no Brasil: como participar?\u003c/h2\u003e\n\u003cp\u003eA comunidade Kotlin no Brasil e \u003cstrong\u003evibrante, acolhedora e em pleno crescimento\u003c/strong\u003e. Diferente de algumas comunidades de tecnologia que podem ser intimidadoras para iniciantes, a comunidade Kotlin brasileira se destaca pela receptividade e pela vontade de ajudar quem esta comecando. Neste guia, vou mostrar todos os caminhos para você se conectar e participar ativamente.\u003c/p\u003e\n\u003ch3 id=\"por-que-participar-de-uma-comunidade\"\u003ePor que participar de uma comunidade?\u003c/h3\u003e\n\u003cp\u003eAntes de listar onde encontrar a comunidade, vale entender por que participar e tao importante para sua carreira:\u003c/p\u003e","title":"Comunidade Kotlin no Brasil: Como Participar? | Kotlin Brasil"},{"content":"Projetos Kotlin para iniciantes: ideias práticas A melhor forma de aprender qualquer linguagem de programação e construindo coisas reais. Nao adianta ficar só lendo tutoriais e assistindo videos \u0026ndash; você precisa escrever código, errar, debugar e resolver problemas. Este guia traz uma lista progressiva de projetos para você praticar Kotlin desde o básico até o intermediário.\nPor que projetos são tao importantes? Projetos pessoais ensinam habilidades que nenhum tutorial consegue cobrir:\nComo planejar e estruturar código do zero Como lidar com problemas inesperados Como pesquisar solucoes quando você trava Como manter a motivacao ao ver resultados concretos Como construir um portfolio que impressiona recrutadores Nível 1: Projetos de console (terminal) Comece com projetos simples que rodam no terminal. Eles focam nos fundamentos da linguagem sem a complexidade de frameworks.\nProjeto 1: Calculadora interativa\nfun main() { println(\u0026#34;=== Calculadora Kotlin ===\u0026#34;) println(\u0026#34;Operações: +, -, *, /\u0026#34;) print(\u0026#34;Primeiro numero: \u0026#34;) val num1 = readLine()?.toDoubleOrNull() ?: run { println(\u0026#34;Numero invalido\u0026#34;) return } print(\u0026#34;Operação: \u0026#34;) val operacao = readLine() ?: return print(\u0026#34;Segundo numero: \u0026#34;) val num2 = readLine()?.toDoubleOrNull() ?: run { println(\u0026#34;Numero invalido\u0026#34;) return } val resultado = when (operacao) { \u0026#34;+\u0026#34; -\u0026gt; num1 + num2 \u0026#34;-\u0026#34; -\u0026gt; num1 - num2 \u0026#34;*\u0026#34; -\u0026gt; num1 * num2 \u0026#34;/\u0026#34; -\u0026gt; if (num2 != 0.0) num1 / num2 else { println(\u0026#34;Erro: divisao por zero\u0026#34;) return } else -\u0026gt; { println(\u0026#34;Operação invalida\u0026#34;) return } } println(\u0026#34;Resultado: $num1 $operacao $num2 = $resultado\u0026#34;) } Projeto 2: Jogo de adivinhacao\nCrie um jogo onde o programa escolhe um número aleatorio e o jogador tenta adivinhar, recebendo dicas de \u0026ldquo;maior\u0026rdquo; ou \u0026ldquo;menor\u0026rdquo;. Conceitos praticados: loops, condicionais, Random.\nProjeto 3: Gerenciador de contatos\nUm sistema de CRUD simples para gerenciar contatos no terminal. Conceitos praticados: listas mutaveis, data classes, funções, entrada do usuário.\ndata class Contato(val nome: String, val telefone: String, val email: String) class GerenciadorContatos { private val contatos = mutableListOf\u0026lt;Contato\u0026gt;() fun adicionar(contato: Contato) { contatos.add(contato) println(\u0026#34;Contato \u0026#39;${contato.nome}\u0026#39; adicionado com sucesso!\u0026#34;) } fun listar() { if (contatos.isEmpty()) { println(\u0026#34;Nenhum contato cadastrado.\u0026#34;) return } contatos.forEachIndexed { indice, contato -\u0026gt; println(\u0026#34;${indice + 1}. ${contato.nome} | ${contato.telefone} | ${contato.email}\u0026#34;) } } fun buscar(termo: String): List\u0026lt;Contato\u0026gt; = contatos.filter { it.nome.contains(termo, ignoreCase = true) || it.email.contains(termo, ignoreCase = true) } fun remover(indice: Int): Boolean { if (indice in contatos.indices) { val removido = contatos.removeAt(indice) println(\u0026#34;Contato \u0026#39;${removido.nome}\u0026#39; removido.\u0026#34;) return true } return false } fun totalContatos(): Int = contatos.size } Projeto 4: Conversor de unidades\nConverta entre diferentes unidades de medida (temperatura, peso, distancia, moedas). Conceitos praticados: funções, when expressions, formatação de números.\nProjeto 5: Quiz interativo\nUm jogo de perguntas e respostas com pontuacao, categorias e feedback imediato. Conceitos praticados: coleções, aleatoriedade, controle de fluxo.\nNível 2: Projetos com persistencia de dados Apos dominar o básico, evolua para projetos que salvam e carregam dados.\nProjeto 6: Diario pessoal com arquivos\nUm diario que salva entradas em arquivos de texto, permitindo consultar entradas por data.\nimport java.io.File import java.time.LocalDate import java.time.format.DateTimeFormatter class DiarioPessoal(private val diretorio: String) { init { File(diretorio).mkdirs() } fun novaEntrada(texto: String) { val hoje = LocalDate.now() val arquivo = File(\u0026#34;$diretorio/${hoje}.txt\u0026#34;) arquivo.appendText(\u0026#34;--- ${hoje.format(DateTimeFormatter.ofPattern(\u0026#34;dd/MM/yyyy HH:mm\u0026#34;))} ---\\n\u0026#34;) arquivo.appendText(\u0026#34;$texto\\n\\n\u0026#34;) println(\u0026#34;Entrada salva com sucesso!\u0026#34;) } fun lerEntrada(data: LocalDate): String? { val arquivo = File(\u0026#34;$diretorio/${data}.txt\u0026#34;) return if (arquivo.exists()) arquivo.readText() else null } fun listarDatas(): List\u0026lt;String\u0026gt; = File(diretorio).listFiles() ?.filter { it.extension == \u0026#34;txt\u0026#34; } ?.map { it.nameWithoutExtension } ?.sorted() ?: emptyList() } Projeto 7: Sistema de notas escolares\nCadastre alunos, disciplinas e notas. Calcule medias, identifique aprovados e reprovados, gere relatorios. Conceitos praticados: mapas, agrupamento, calculos com coleções.\nProjeto 8: Rastreador de habitos\nRegistre habitos diarios e visualize estatisticas no terminal (dias seguidos, porcentagem de conclusão, gráficos simples com caracteres ASCII).\nNível 3: Projetos com APIs e rede Projeto 9: Consulta de CEP\nUse a API dos Correios (ViaCEP) para buscar enderecos a partir de um CEP. Conceitos praticados: HTTP clients, JSON parsing, coroutines.\nimport kotlinx.coroutines.runBlocking import io.ktor.client.* import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.Serializable @Serializable data class Endereco( val cep: String, val logradouro: String, val bairro: String, val localidade: String, val uf: String ) suspend fun buscarCEP(cep: String): Endereco? { val client = HttpClient { install(ContentNegotiation) { json() } } return try { client.get(\u0026#34;https://viacep.com.br/ws/$cep/json/\u0026#34;).body\u0026lt;Endereco\u0026gt;() } catch (e: Exception) { println(\u0026#34;Erro ao buscar CEP: ${e.message}\u0026#34;) null } finally { client.close() } } fun main() = runBlocking { print(\u0026#34;Digite o CEP: \u0026#34;) val cep = readLine()?.replace(\u0026#34;-\u0026#34;, \u0026#34;\u0026#34;) ?: return@runBlocking val endereco = buscarCEP(cep) if (endereco != null) { println(\u0026#34;Logradouro: ${endereco.logradouro}\u0026#34;) println(\u0026#34;Bairro: ${endereco.bairro}\u0026#34;) println(\u0026#34;Cidade: ${endereco.localidade} - ${endereco.uf}\u0026#34;) } else { println(\u0026#34;CEP nao encontrado.\u0026#34;) } } Projeto 10: Bot do clima\nConsulte APIs de previsao do tempo e exiba informações formatadas no terminal.\nNível 4: Projetos Android com Jetpack Compose Projeto 11: App de lista de compras\nUm aplicativo Android simples onde você adiciona, marca como comprado e remove itens. Conceitos praticados: Composables, state management, listas.\nProjeto 12: Cronometro e timer\nApp com funcionalidade de cronometro e timer com alarme. Conceitos praticados: LaunchedEffect, coroutines no Compose, notificacoes.\nProjeto 13: App de anotações\nUm app de notas com persistencia local usando Room. Conceitos praticados: Room Database, ViewModel, navegação entre telas.\nNível 5: Projetos backend Projeto 14: API de encurtador de URL\nCrie uma API que recebe URLs longas e retorna versões encurtadas. Conceitos praticados: Ktor/Spring Boot, banco de dados, APIs REST.\nProjeto 15: Sistema de votacao\nUma API para criar enquetes e registrar votos, com resultados em tempo real. Conceitos praticados: WebSockets, concorrência, válidação de dados.\nDicas para maximizar o aprendizado com projetos Comece pequeno e evolua: não tente criar algo complexo de cara. Comece com o minimo viável e va adicionando funcionalidades.\nUse Git desde o primeiro projeto: aprenda a versionar seu código. Isso também constroi seu portfolio no GitHub.\nEscreva testes: mesmo para projetos simples, tente escrever pelo menos alguns testes. Isso desenvolve uma habilidade essencial.\nRefatore sem medo: depois que o projeto funciona, volte e melhore o código. Compare a versão inicial com a refatorada.\nDocumente suas decisoes: escreva comentarios explicando por que você fez determinadas escolhas. Isso ajuda na revisao futura.\nPros e contras de diferentes tipos de projetos Projetos de terminal:\nPro: foco nos fundamentos sem distracao de UI Pro: rápidos para implementar Contra: menos motivadores visualmente Projetos Android:\nPro: resultado visual imediato e motivador Pro: habilidade diretamente aplicavel no mercado Contra: curva de aprendizado maior (precisa aprender Compose) Projetos backend:\nPro: habilidade muito valorizada no mercado Pro: fundamentos transferiveis para qualquer tecnologia Contra: resultado menos visivel para mostrar a outros Perguntas relacionadas Como praticar Kotlin? Como aprender Kotlin em 2026? Quanto tempo leva para aprender Kotlin? Kotlin e difícil de aprender? Melhor IDE para Kotlin ","permalink":"https://kotlin.dev.br/perguntas/kotlin-projetos-iniciantes/","summary":"\u003ch2 id=\"projetos-kotlin-para-iniciantes-ideias-práticas\"\u003eProjetos Kotlin para iniciantes: ideias práticas\u003c/h2\u003e\n\u003cp\u003eA melhor forma de aprender qualquer linguagem de programação e construindo coisas reais. Nao adianta ficar só lendo tutoriais e assistindo videos \u0026ndash; você precisa \u003cstrong\u003eescrever código, errar, debugar e resolver problemas\u003c/strong\u003e. Este guia traz uma lista progressiva de projetos para você praticar Kotlin desde o básico até o intermediário.\u003c/p\u003e\n\u003ch3 id=\"por-que-projetos-são-tao-importantes\"\u003ePor que projetos são tao importantes?\u003c/h3\u003e\n\u003cp\u003eProjetos pessoais ensinam habilidades que nenhum tutorial consegue cobrir:\u003c/p\u003e","title":"Projetos Kotlin para Iniciantes: Ideias Práticas | Kotlin Brasil"},{"content":"Como praticar Kotlin? Aprender a teoria é importante, mas a prática é o que transforma conhecimento em habilidade real. Se você quer realmente dominar Kotlin, precisa colocar a mao no código todos os dias. Neste guia, vou mostrar as melhores formas de praticar, desde exercícios para iniciantes até estrategias avançadas para quem já tem alguma experiência.\n1. Kotlin Playground e REPL O jeito mais rápido de começar a praticar e usando o Kotlin Playground no navegador. Nao precisa instalar nada, basta abrir e começar a digitar código.\nPara prática local, você pode usar o REPL (Read-Eval-Print Loop) do Kotlin:\n// Abra o terminal e digite: kotlinc // Isso abre o REPL interativo onde voce pode testar codigo rapidamente // Experimente no Playground ou REPL: fun inverterPalavras(frase: String): String = frase.split(\u0026#34; \u0026#34;).reversed().joinToString(\u0026#34; \u0026#34;) fun contarVogais(texto: String): Int = texto.lowercase().count { it in \u0026#34;aeiou\u0026#34; } fun main() { println(inverterPalavras(\u0026#34;Kotlin e incrivel\u0026#34;)) // Saida: \u0026#34;incrivel e Kotlin\u0026#34; println(contarVogais(\u0026#34;Desenvolvimento de software\u0026#34;)) // Saida: 11 } 2. Kotlin Koans Os Kotlin Koans são exercícios interativos oficiais criados pela JetBrains. Eles cobrem os principais recursos da linguagem de forma progressiva e são excelentes para quem esta comecando.\nOs Koans cobrem topicos como:\nIntrodução a sintaxe Convenções e operadores Coleções e transformacoes Propriedades e delegação Builders e DSLs Generics 3. Plataformas de desafios de programação Resolver desafios em plataformas online e uma forma excelente de praticar lógica e sintaxe simultaneamente.\nPlataformas recomendadas:\nHackerRank: tem seção específica para Kotlin com problemas categorizados por dificuldade LeetCode: aceita solucoes em Kotlin e e otimo para preparacao de entrevistas Exercism: oferece trilha de Kotlin com mentoria voluntaria CodeWars: desafios em formato de \u0026ldquo;katas\u0026rdquo; com dificuldade progressiva // Exemplo de desafio tipico: encontrar o segundo maior numero fun segundoMaior(numeros: List\u0026lt;Int\u0026gt;): Int? { if (numeros.size \u0026lt; 2) return null return numeros.distinct().sortedDescending().getOrNull(1) } // Desafio: verificar se uma string e palindromo fun ePalindromo(texto: String): Boolean { val limpo = texto.lowercase().filter { it.isLetterOrDigit() } return limpo == limpo.reversed() } // Desafio: FizzBuzz funcional fun fizzBuzz(n: Int): List\u0026lt;String\u0026gt; = (1..n).map { numero -\u0026gt; when { numero % 15 == 0 -\u0026gt; \u0026#34;FizzBuzz\u0026#34; numero % 3 == 0 -\u0026gt; \u0026#34;Fizz\u0026#34; numero % 5 == 0 -\u0026gt; \u0026#34;Buzz\u0026#34; else -\u0026gt; numero.toString() } } fun main() { println(segundoMaior(listOf(5, 3, 8, 1, 9, 2))) // 8 println(ePalindromo(\u0026#34;A man a plan a canal Panama\u0026#34;)) // true println(fizzBuzz(15)) } 4. Projetos pessoais progressivos A melhor prática vem de construir algo real. Aqui esta uma progressao recomendada de projetos:\nNível iniciante:\nCalculadora de linha de comando Lista de tarefas (to-do list) no terminal Conversor de unidades (temperatura, moedas, medidas) Jogo de adivinhacao de números Nível intermediário:\nAPI REST com Ktor ou Spring Boot App Android simples com Jetpack Compose (lista de notas, calculadora de gorjeta) Leitor de RSS que consome feeds da internet Sistema de gerenciamento de biblioteca (CRUD completo) Nível avançado:\nApp multiplataforma com KMP Clone simplificado de um app popular (lista de compras, previsao do tempo) Contribuicao em projetos open source Ferramenta CLI com kotlinx-cli // Projeto pratico: calculadora de IMC fun calcularIMC(peso: Double, altura: Double): Double = peso / (altura * altura) fun classificarIMC(imc: Double): String = when { imc \u0026lt; 18.5 -\u0026gt; \u0026#34;Abaixo do peso\u0026#34; imc \u0026lt; 25.0 -\u0026gt; \u0026#34;Peso normal\u0026#34; imc \u0026lt; 30.0 -\u0026gt; \u0026#34;Sobrepeso\u0026#34; imc \u0026lt; 35.0 -\u0026gt; \u0026#34;Obesidade grau I\u0026#34; imc \u0026lt; 40.0 -\u0026gt; \u0026#34;Obesidade grau II\u0026#34; else -\u0026gt; \u0026#34;Obesidade grau III\u0026#34; } fun main() { print(\u0026#34;Digite seu peso (kg): \u0026#34;) val peso = readLine()?.toDoubleOrNull() ?: return print(\u0026#34;Digite sua altura (m): \u0026#34;) val altura = readLine()?.toDoubleOrNull() ?: return val imc = calcularIMC(peso, altura) val classificacao = classificarIMC(imc) println(\u0026#34;Seu IMC: ${\u0026#34;%.1f\u0026#34;.format(imc)}\u0026#34;) println(\u0026#34;Classificacao: $classificacao\u0026#34;) } 5. Contribuicao em projetos open source Contribuir em projetos open source e uma das melhores formas de praticar Kotlin em um contexto profissional. Você aprende padrões de código real, passa por code review e interage com outros desenvolvedores.\nComo começar:\nProcure projetos Kotlin no GitHub com a tag \u0026ldquo;good first issue\u0026rdquo; Leia o código existente para entender os padrões Comece com contribuicoes pequenas (correção de bugs, melhoria de documentação) Evolua para contribuicoes maiores conforme ganha confianca Projetos brasileiros de Kotlin para contribuir:\nBibliotecas e ferramentas da comunidade Projetos de aprendizado colaborativo Aplicativos open source em Kotlin 6. Estudo de código alheio Ler código escrito por outros desenvolvedores experientes e uma forma poderosa de aprendizado. Análise projetos open source populares em Kotlin e tente entender:\nComo eles organizam o código Quais padrões de projeto utilizam Como lidam com tratamento de erros Como escrevem testes 7. Testes automatizados como prática Escrever testes e uma habilidade fundamental e também uma otima forma de praticar:\n// Praticando com testes unitarios import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.* class CalculadoraTest { private val calc = Calculadora() @Test fun `soma de dois numeros positivos`() { assertEquals(5, calc.somar(2, 3)) } @Test fun `divisao por zero lanca excecao`() { assertThrows(ArithmeticException::class.java) { calc.dividir(10, 0) } } @Test fun `lista filtrada corretamente`() { val numeros = listOf(1, 2, 3, 4, 5, 6) val pares = numeros.filter { it % 2 == 0 } assertEquals(listOf(2, 4, 6), pares) } } 8. Habitos diarios que aceleram o aprendizado 30 minutos por dia: a consistencia vale mais que sessoes longas esporadicas Caderno de anotações: anote conceitos novos, erros cometidos e solucoes encontradas Ensine alguem: explicar um conceito para outra pessoa consolida seu próprio entendimento Revise código antigo: volte a projetos anteriores e melhore-os com o que aprendeu Participe de comunidades: tire duvidas, responda perguntas de outros e troque experiencias Pros e contras de cada método de prática Plataformas de desafios:\nPro: exercícios variados e com dificuldade progressiva Pro: preparacao para entrevistas tecnicas Contra: problemas abstratos que nem sempre refletem o trabalho real Projetos pessoais:\nPro: motivacao pessoal e resultado tangivel Pro: experiência proxima ao trabalho profissional Contra: pode ser difícil manter a disciplina sozinho Contribuicao open source:\nPro: experiência real com code review e colaboracao Pro: networking com outros desenvolvedores Contra: curva de aprendizado inicial para entender projetos grandes O mais importante Nao existe uma única forma certa de praticar. O segredo e combinar diferentes abordagens e manter a constancia. Comece com o que for mais confortavel para você e va expandindo conforme ganha confianca. O mais importante e escrever código todos os dias, mesmo que seja pouco.\nPerguntas relacionadas Como aprender Kotlin em 2026? Quanto tempo leva para aprender Kotlin? Projetos Kotlin para iniciantes Kotlin e difícil de aprender? Melhor IDE para Kotlin ","permalink":"https://kotlin.dev.br/perguntas/como-praticar-kotlin/","summary":"\u003ch2 id=\"como-praticar-kotlin\"\u003eComo praticar Kotlin?\u003c/h2\u003e\n\u003cp\u003eAprender a teoria é importante, mas \u003cstrong\u003ea prática é o que transforma conhecimento em habilidade real\u003c/strong\u003e. Se você quer realmente dominar Kotlin, precisa colocar a mao no código todos os dias. Neste guia, vou mostrar as melhores formas de praticar, desde exercícios para iniciantes até estrategias avançadas para quem já tem alguma experiência.\u003c/p\u003e\n\u003ch3 id=\"1-kotlin-playground-e-repl\"\u003e1. Kotlin Playground e REPL\u003c/h3\u003e\n\u003cp\u003eO jeito mais rápido de começar a praticar e usando o \u003ca href=\"https://play.kotlinlang.org/\"\u003eKotlin Playground\u003c/a\u003e no navegador. Nao precisa instalar nada, basta abrir e começar a digitar código.\u003c/p\u003e","title":"Como Praticar Kotlin? Guia Completo | Kotlin Brasil"},{"content":"Kotlin ou Flutter: qual escolher? Essa é uma das comparações mais comuns no mundo do desenvolvimento mobile, mas é importante entender que estamos comparando coisas de naturezas diferentes. Kotlin é uma linguagem de programação; Flutter é um framework de UI multiplataforma que usa a linguagem Dart. Dito isso, vamos analisar as duas abordagens para desenvolvimento mobile de forma justa e detalhada.\nEntendendo as diferenças fundamentais Kotlin para mobile pode significar duas coisas:\nKotlin nativo para Android: desenvolvimento exclusivo para Android usando Jetpack Compose Kotlin Multiplatform (KMP): compartilhamento de lógica entre Android e iOS, com UI nativa em cada plataforma Flutter é um framework do Google que permite criar apps para Android, iOS, web e desktop usando uma única base de código, incluindo a interface. Flutter usa seu próprio motor de renderizacao (Skia/Impeller) é a linguagem Dart.\nComparação técnica // Kotlin com Jetpack Compose - UI nativa Android @Composable fun ListaDeProdutos(produtos: List\u0026lt;Produto\u0026gt;) { LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = PaddingValues(16.dp) ) { items(produtos) { produto -\u0026gt; CartaoProduto(produto) } } } @Composable fun CartaoProduto(produto: Produto) { Card( modifier = Modifier .fillMaxWidth() .padding(vertical = 8.dp) ) { Row(modifier = Modifier.padding(16.dp)) { Column(modifier = Modifier.weight(1f)) { Text( text = produto.nome, style = MaterialTheme.typography.titleMedium ) Text( text = \u0026#34;R$ ${\u0026#34;%.2f\u0026#34;.format(produto.preco)}\u0026#34;, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.primary ) } if (produto.emEstoque) { Badge { Text(\u0026#34;Disponivel\u0026#34;) } } } } } O equivalente em Flutter/Dart seria estruturalmente similar, mas com widgets próprios do Flutter em vez de componentes nativos do Android.\nKotlin nativo vs Flutter: análise detalhada Performance:\nKotlin nativo compila diretamente para bytecode da plataforma, oferecendo performance maxima Flutter usa seu próprio motor de renderizacao, que e muito performatico mas adiciona uma camada extra Para a maioria dos apps, a diferenca de performance e imperceptivel para o usuário Em casos extremos (animacoes complexas, processamento pesado), Kotlin nativo pode ter vantagem UI e experiência do usuário:\nKotlin com Compose segue as guidelines do Material Design nativamente no Android Flutter recria os componentes visuais com seu motor próprio, o que pode resultar em diferenças sutis Apps Kotlin nativos se integram perfeitamente com o sistema operacional Flutter permite customizacao visual extrema e consistente entre plataformas Multiplataforma:\nFlutter cobre Android, iOS, web e desktop com uma única base de código (incluindo UI) KMP compartilha lógica de negocios mas mantém UI nativa em cada plataforma Compose Multiplatform esta evoluindo para permitir compartilhamento de UI também Flutter e mais maduro como solução multiplataforma completa Mercado de trabalho no Brasil O mercado brasileiro apresenta demanda significativa para ambas as tecnologias:\nKotlin:\nForte demanda em empresas de médio e grande porte Salários geralmente mais altos Muitas vagas em fintechs e empresas de tecnologia Combinacao com Java abre ainda mais portas Flutter:\nCrescimento explosivo nos ultimos anos Popular em startups e agencias de desenvolvimento Atrativo para empresas que precisam de iOS e Android com equipe reduzida Comunidade brasileira muito ativa Pros e contras Kotlin (nativo + KMP):\nPros:\nPerformance nativa maxima Integração perfeita com APIs do sistema operacional Ecossistema maduro de bibliotecas JVM Null safety e coroutines como vantagens da linguagem Jetpack Compose e moderno e produtivo Valorizacao alta no mercado Contras:\nDesenvolvimento exclusivo Android se não usar KMP KMP ainda menos maduro que Flutter para multiplataforma Precisa de Swift/SwiftUI para UI no iOS quando usando KMP Requer duas habilidades de UI para cobertura completa Flutter:\nPros:\nUma única base de código para Android, iOS, web e desktop Hot reload acelera muito o desenvolvimento Comunidade grande e ecossistema de pacotes robusto Ideal para MVPs e startups com recursos limitados Widgets altamente customizaveis Contras:\nTamanho do app final geralmente maior Dart e menos popular que Kotlin no mercado geral Integracoes nativas exigem platform channels, que podem ser complexos Look and feel pode não ser 100% nativo Quando escolher cada um Escolha Kotlin nativo quando:\nSeu projeto e exclusivamente Android Performance maxima e crítica Você precisa de integração profunda com APIs do Android A empresa já tem equipe Kotlin Escolha KMP quando:\nVocê quer compartilhar lógica entre Android e iOS A equipe domina Kotlin e pode lidar com SwiftUI no iOS A lógica de negocios e complexa e precisa ser consistente Escolha Flutter quando:\nPrecisa de app para Android e iOS com equipe reduzida O prazo e apertado e você precisa de velocidade de desenvolvimento A customizacao visual e mais importante que o look nativo Você também precisa de versão web Cenarios práticos // Exemplo de logica compartilhada com KMP // Este codigo roda tanto no Android quanto no iOS class CarrinhoDeCompras { private val itens = mutableListOf\u0026lt;ItemCarrinho\u0026gt;() fun adicionar(produto: Produto, quantidade: Int) { val existente = itens.find { it.produto.id == produto.id } if (existente != null) { existente.quantidade += quantidade } else { itens.add(ItemCarrinho(produto, quantidade)) } } fun remover(produtoId: Long) { itens.removeAll { it.produto.id == produtoId } } fun calcularTotal(): Double = itens.sumOf { it.produto.preco * it.quantidade } fun obterResumo(): ResumoCarrinho = ResumoCarrinho( quantidadeItens = itens.sumOf { it.quantidade }, valorTotal = calcularTotal(), itens = itens.toList() ) } data class ItemCarrinho(val produto: Produto, var quantidade: Int) data class ResumoCarrinho( val quantidadeItens: Int, val valorTotal: Double, val itens: List\u0026lt;ItemCarrinho\u0026gt; ) A tendencia para o futuro A tendencia e que tanto Kotlin quanto Flutter continuem crescendo. O Compose Multiplatform pode eventualmente posicionar Kotlin como competidor direto do Flutter no espaco de UI compartilhada, mas isso ainda esta em evolução.\nA melhor estrategia para um desenvolvedor mobile em 2026 e conhecer pelo menos uma das duas abordagens profundamente e ter familiaridade com a outra. Isso maximiza suas opções de carreira e permite escolher a ferramenta certa para cada projeto.\nPerguntas relacionadas Kotlin pode ser usado para iOS? E fácil encontrar emprego com Kotlin? O que é Kotlin Multiplatform? Kotlin vale a pena em 2026? Kotlin ou Java: qual aprender primeiro? ","permalink":"https://kotlin.dev.br/perguntas/kotlin-ou-flutter/","summary":"\u003ch2 id=\"kotlin-ou-flutter-qual-escolher\"\u003eKotlin ou Flutter: qual escolher?\u003c/h2\u003e\n\u003cp\u003eEssa é uma das comparações mais comuns no mundo do desenvolvimento mobile, mas é importante entender que \u003cstrong\u003eestamos comparando coisas de naturezas diferentes\u003c/strong\u003e. Kotlin é uma linguagem de programação; Flutter é um framework de UI multiplataforma que usa a linguagem Dart. Dito isso, vamos analisar as duas abordagens para desenvolvimento mobile de forma justa e detalhada.\u003c/p\u003e\n\u003ch3 id=\"entendendo-as-diferenças-fundamentais\"\u003eEntendendo as diferenças fundamentais\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eKotlin para mobile\u003c/strong\u003e pode significar duas coisas:\u003c/p\u003e","title":"Kotlin ou Flutter: Qual Escolher? | Kotlin Brasil"},{"content":"Kotlin vale a pena em 2026? Sim, Kotlin vale muito a pena em 2026. A linguagem esta em um dos seus melhores momentos, com adoção crescente em múltiplas areas, mercado de trabalho aquecido e investimentos pesados tanto do Google quanto da JetBrains. Mas vamos fundamentar essa afirmacao com dados, tendências e analises concretas.\nO momento atual do Kotlin Em 2026, Kotlin ocupa uma posicao solida no ecossistema de desenvolvimento de software. A linguagem não é mais apenas \u0026ldquo;a alternativa ao Java para Android\u0026rdquo; \u0026ndash; ela se expandiu significativamente para backend, multiplataforma e até mesmo desenvolvimento de scripts e ferramentas de linha de comando.\nAlguns marcos relevantes:\nO Google continua posicionando Kotlin como a linguagem prioritaria para Android Kotlin Multiplatform atingiu estabilidade (saiu de beta em 2023) e esta sendo adotado por empresas de todos os tamanhos Compose Multiplatform permite compartilhar UI entre Android, iOS, desktop e web Grandes empresas brasileiras como Nubank, iFood, PicPay, Mercado Livre e bancos tradicionais utilizam Kotlin em producao Mercado de trabalho: números concretos O mercado de trabalho para Kotlin no Brasil apresenta tendências claras:\nVagas em crescimento: a quantidade de vagas que mencionam Kotlin tem crescido ano a ano, tanto para posicoes presenciais quanto remotas.\nSalários competitivos: desenvolvedores Kotlin no Brasil ganham, em media, acima do mercado de tecnologia. Posicoes seniors em grandes empresas superam facilmente faixas salariais de outras linguagens populares.\nVagas internacionais remotas: profissionais brasileiros de Kotlin com ingles fluente tem acesso a vagas remotas internacionais que pagam em dolar ou euro, multiplicando significativamente a remuneracao.\n// O tipo de codigo que empresas esperam de um dev Kotlin senior em 2026 // Arquitetura moderna com Kotlin class GerenciadorDeTransacoes( private val repositorio: RepositorioTransacao, private val validador: ValidadorTransacao, private val notificador: ServicoNotificacao ) { suspend fun processarTransacao(transacao: Transacao): Resultado\u0026lt;Confirmacao\u0026gt; { // Validação com sealed class return when (val validação = validador.validar(transacao)) { is Validação.Sucesso -\u0026gt; executarTransacao(transacao) is Validação.Falha -\u0026gt; Resultado.Erro(validação.motivo) } } private suspend fun executarTransacao(transacao: Transacao): Resultado\u0026lt;Confirmacao\u0026gt; { return try { val confirmacao = repositorio.salvar(transacao) notificador.enviar( Notificacao( destinatario = transacao.usuarioId, mensagem = \u0026#34;Transacao ${confirmacao.codigo} processada\u0026#34; ) ) Resultado.Sucesso(confirmacao) } catch (e: Exception) { Resultado.Erro(\u0026#34;Falha ao processar: ${e.message}\u0026#34;) } } } sealed class Resultado\u0026lt;out T\u0026gt; { data class Sucesso\u0026lt;T\u0026gt;(val dados: T) : Resultado\u0026lt;T\u0026gt;() data class Erro(val mensagem: String) : Resultado\u0026lt;Nothing\u0026gt;() } sealed class Validação { data object Sucesso : Validação() data class Falha(val motivo: String) : Validação() } Areas onde Kotlin brilha em 2026 1. Desenvolvimento Android\nNao há duvida de que Kotlin e a linguagem do Android. O Jetpack Compose amadureceu e se tornou o padrão para novas interfaces. Praticamente toda documentação nova do Android e escrita em Kotlin, e muitas APIs são projetadas com Kotlin em mente.\n2. Backend com Kotlin\nO uso de Kotlin no backend continua crescendo. Spring Boot com Kotlin e uma combinacao poderosa usada por empresas de todos os tamanhos. Ktor, o framework nativo de Kotlin, também ganhou tracao significativa para microsserviços e APIs.\n3. Kotlin Multiplatform\nKMP saiu do experimental e se consolidou como uma opção real para compartilhamento de código entre plataformas. Empresas como Netflix, Cash App e Touchlab demonstram que a tecnologia funciona em escala de producao.\n4. Compose Multiplatform\nA possibilidade de compartilhar não apenas lógica, mas também a interface do usuário entre Android, iOS, desktop e web usando Compose e um diferencial único que nenhuma outra tecnologia oferece da mesma forma.\nAnálise de tendências Tendências positivas:\nAdoção corporativa crescente no Brasil e no mundo Investimento contínuo da JetBrains e do Google Ecossistema de bibliotecas multiplataforma em expansao Comunidade ativa e crescente Novas versões da linguagem com melhorias significativas regularmente Preocupacoes:\nConcorrência com Flutter no espaco multiplataforma Swift permanece forte no ecossistema Apple Rust e Go atraem atencao para backend de alta performance Menor quantidade de material em português comparado com JavaScript ou Python Pros e contras de investir em Kotlin em 2026 Pros:\nLinguagem moderna, expressiva e segura Demanda de mercado crescente e salários acima da media Versatilidade: mobile, backend, desktop, multiplataforma Interoperabilidade com Java garante acesso a um ecossistema enorme Google e JetBrains investem pesado no futuro da linguagem Coroutines e null safety são vantagens competitivas reais Curva de aprendizado acessivel para quem vem de Java ou outras linguagens OOP Contras:\nEcossistema menor que Java, JavaScript ou Python para algumas areas Kotlin Multiplatform, embora estavel, ainda e menos maduro que solucoes nativas Poucas oportunidades em areas como data science ou machine learning (Python domina) Tempo de compilação pode ser mais lento que Java em projetos grandes Para quem Kotlin vale a pena? Definitivamente vale a pena se você:\nQuer trabalhar com desenvolvimento mobile Android Busca uma linguagem moderna para backend na JVM Deseja uma solução multiplataforma que mantenha qualidade nativa Ja conhece Java e quer evoluir para uma linguagem mais produtiva Procura bons salários e mercado aquecido Talvez não seja a melhor opção se você:\nQuer focar exclusivamente em desenvolvimento iOS (Swift seria mais direto) Seu interesse principal e data science ou machine learning (Python domina) Precisa desenvolver sistemas embarcados (C/C++ são mais adequados) Quer trabalhar exclusivamente com frontend web (JavaScript/TypeScript dominam) O futuro do Kotlin As perspectivas para os próximos anos são muito promissoras. A JetBrains continua investindo em:\nMelhorias no compilador K2 para compilação mais rápida Evolução do Compose Multiplatform Novos recursos da linguagem em cada versão Ferramentas e suporte aprimorados O Google mantém Kotlin como linguagem prioritaria para Android e continua expandindo o suporte em suas bibliotecas e ferramentas. Nao há nenhum sinal de que esse compromisso va mudar.\nConselho final Se você esta em duvida sobre investir seu tempo em Kotlin, a resposta em 2026 e um sim muito claro. A linguagem oferece um equilibrio raro entre produtividade, segurança, versatilidade e oportunidades de mercado. Poucos investimentos em aprendizado técnico oferecem um retorno tao consistente quanto dominar Kotlin neste momento.\nComece hoje, pratique diariamente, e em poucos meses você tera uma habilidade altamente valorizada pelo mercado brasileiro e internacional. Se quiser ampliar seu repertório backend, linguagens como Go e Python complementam muito bem o perfil de quem domina Kotlin.\nPerguntas relacionadas E fácil encontrar emprego com Kotlin? Salário de desenvolvedor Kotlin Kotlin ou Java: qual aprender primeiro? Quanto tempo leva para aprender Kotlin? O que é Kotlin Multiplatform? ","permalink":"https://kotlin.dev.br/perguntas/kotlin-vale-a-pena-2026/","summary":"\u003ch2 id=\"kotlin-vale-a-pena-em-2026\"\u003eKotlin vale a pena em 2026?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eSim, Kotlin vale muito a pena em 2026.\u003c/strong\u003e A linguagem esta em um dos seus melhores momentos, com adoção crescente em múltiplas areas, mercado de trabalho aquecido e investimentos pesados tanto do Google quanto da JetBrains. Mas vamos fundamentar essa afirmacao com dados, tendências e analises concretas.\u003c/p\u003e\n\u003ch3 id=\"o-momento-atual-do-kotlin\"\u003eO momento atual do Kotlin\u003c/h3\u003e\n\u003cp\u003eEm 2026, Kotlin ocupa uma posicao solida no ecossistema de desenvolvimento de software. A linguagem não é mais apenas \u0026ldquo;a alternativa ao Java para Android\u0026rdquo; \u0026ndash; ela se expandiu significativamente para backend, multiplataforma e até mesmo desenvolvimento de scripts e ferramentas de linha de comando.\u003c/p\u003e","title":"Kotlin Vale a Pena em 2026? | Kotlin Brasil"},{"content":"Kotlin pode ser usado para criar jogos? Sim, e possível criar jogos com Kotlin, embora a linguagem não seja a escolha mais popular no mundo do desenvolvimento de jogos. Kotlin pode ser utilizada com algumas engines e frameworks específicos, além de ser viável para jogos Android nativos. Vamos explorar todas as opções, suas vantagens e limitações, para você decidir se faz sentido usar Kotlin no seu projeto de gamedev.\nO cenário do Kotlin no desenvolvimento de jogos O desenvolvimento de jogos e historicamente dominado por linguagens como C++, C# (com Unity) e mais recentemente GDScript (com Godot). Kotlin não é a primeira linguagem que vem a mente quando se fala em gamedev, mas existem caminhos viáveis e interessantes para quem quer combinar seu conhecimento de Kotlin com a criação de jogos.\nOpções para desenvolvimento de jogos com Kotlin 1. LibGDX - A opção mais madura\nLibGDX é um framework de desenvolvimento de jogos em Java que funciona perfeitamente com Kotlin. E a opção mais consolidada e usada pela comunidade Kotlin para gamedev. Permite criar jogos para desktop, Android, iOS e web.\nimport com.badlogic.gdx.ApplicationAdapter import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.GL20 import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.g2d.SpriteBatch class MeuJogo : ApplicationAdapter() { private lateinit var batch: SpriteBatch private lateinit var textura: Texture private var posX = 0f private var posY = 0f private val velocidade = 200f override fun create() { batch = SpriteBatch() textura = Texture(\u0026#34;personagem.png\u0026#34;) posX = Gdx.graphics.width / 2f posY = Gdx.graphics.height / 2f } override fun render() { // Atualizar posicao val delta = Gdx.graphics.deltaTime if (Gdx.input.isTouched) { val alvoX = Gdx.input.x.toFloat() val alvoY = (Gdx.graphics.height - Gdx.input.y).toFloat() posX += (alvoX - posX) * velocidade * delta posY += (alvoY - posY) * velocidade * delta } // Renderizar Gdx.gl.glClearColor(0.15f, 0.15f, 0.2f, 1f) Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) batch.begin() batch.draw(textura, posX, posY) batch.end() } override fun dispose() { batch.dispose() textura.dispose() } } 2. KorGE - Engine nativa de Kotlin\nKorGE e uma engine de jogos escrita inteiramente em Kotlin e projetada para ser multiplataforma. E a opção mais \u0026ldquo;Kotlin-nativa\u0026rdquo; disponivel e suporta JVM, JavaScript, Android e iOS.\nimport korlibs.korge.* import korlibs.korge.scene.* import korlibs.korge.view.* import korlibs.image.color.* import korlibs.math.geom.* suspend fun main() = Korge(windowSize = Size(800, 600), backgroundColor = Colors.DARKBLUE) { sceneContainer().changeTo { CenaPrincipal() } } class CenaPrincipal : Scene() { override suspend fun SContainer.sceneMain() { val jogador = solidRect(50, 50, Colors.GREEN).apply { position(375, 275) } val pontuacao = text(\u0026#34;Pontos: 0\u0026#34;, textSize = 24.0, color = Colors.WHITE).apply { position(10, 10) } var pontos = 0 addUpdater { // Movimentacao simples val vel = 3.0 if (views.input.keys.pressing(korlibs.event.Key.LEFT)) jogador.x -= vel if (views.input.keys.pressing(korlibs.event.Key.RIGHT)) jogador.x += vel if (views.input.keys.pressing(korlibs.event.Key.UP)) jogador.y -= vel if (views.input.keys.pressing(korlibs.event.Key.DOWN)) jogador.y += vel } jogador.onClick { pontos++ pontuacao.text = \u0026#34;Pontos: $pontos\u0026#34; } } } 3. Jogos Android nativos com Canvas\nPara jogos mais simples, você pode criar jogos Android diretamente usando Canvas e Kotlin, sem nenhum framework adicional.\nclass GameView(context: Context) : SurfaceView(context), Runnable { private var thread: Thread? = null private var rodando = false private val paint = Paint() private var jogadorX = 500f private var jogadorY = 800f private val jogadorRaio = 40f private val obstaculos = mutableListOf\u0026lt;Obstaculo\u0026gt;() private var pontuacao = 0 data class Obstaculo(var x: Float, var y: Float, val largura: Float, val altura: Float, var velocidade: Float) override fun run() { while (rodando) { if (holder.surface.isValid) { val canvas = holder.lockCanvas() atualizar() desenhar(canvas) holder.unlockCanvasAndPost(canvas) } } } private fun atualizar() { obstaculos.forEach { it.y += it.velocidade } obstaculos.removeAll { it.y \u0026gt; height } if (obstaculos.size \u0026lt; 5 \u0026amp;\u0026amp; Math.random() \u0026gt; 0.97) { obstaculos.add( Obstaculo( x = (Math.random() * width).toFloat(), y = 0f, largura = 60f, altura = 60f, velocidade = (3..8).random().toFloat() ) ) } pontuacao++ } private fun desenhar(canvas: Canvas) { canvas.drawColor(Color.BLACK) paint.color = Color.GREEN canvas.drawCircle(jogadorX, jogadorY, jogadorRaio, paint) paint.color = Color.RED obstaculos.forEach { canvas.drawRect(it.x, it.y, it.x + it.largura, it.y + it.altura, paint) } paint.color = Color.WHITE paint.textSize = 48f canvas.drawText(\u0026#34;Pontos: $pontuacao\u0026#34;, 20f, 60f, paint) } } Pros e contras de usar Kotlin para jogos Vantagens:\nSintaxe concisa e produtiva reduz o tempo de desenvolvimento Null safety previne crashes comuns em jogos Coroutines facilitam programação assíncrona (carregamento de assets, IA) Interoperabilidade com Java abre acesso a todo ecossistema de bibliotecas KorGE oferece experiência totalmente Kotlin-nativa Excelente para jogos mobile Android Desvantagens:\nMenos recursos e tutoriais de gamedev comparado com C# (Unity) ou C++ Performance pode ser inferior a linguagens compiladas nativamente para jogos AAA Comunidade de gamedev em Kotlin e pequena Poucas engines dedicadas comparado com outras linguagens Nao e viável para jogos de alta performance grafica (AAA) Para quais tipos de jogos Kotlin e indicado? Kotlin funciona muito bem para:\nJogos 2D indie e casual Jogos mobile para Android Prototipos rápidos Jogos multiplataforma simples Game jams e projetos pessoais Kotlin não e ideal para:\nJogos AAA com gráficos intensivos Jogos que exigem maximo desempenho de hardware Projetos que precisam de engines como Unreal Engine Comparação com outras opções de gamedev Tecnologia Facilidade Performance Ecossistema Plataformas Kotlin + LibGDX Alta Boa Medio Multi Kotlin + KorGE Alta Boa Pequeno Multi C# + Unity Media Muito boa Enorme Multi C++ + Unreal Baixa Excelente Enorme Multi GDScript + Godot Alta Boa Grande Multi Conselho prático Se você já sabe Kotlin e quer experimentar gamedev, comece com KorGE ou LibGDX. São otimos para aprender conceitos de desenvolvimento de jogos sem precisar aprender uma linguagem nova. Se gamedev for seu foco principal de carreira, considere investir em Unity com C# ou Godot com GDScript, que tem ecossistemas muito maiores.\nPara jogos Android especificamente, Kotlin e uma escolha natural e eficiente. Muitos jogos casuais na Google Play foram criados com Kotlin, e a integração com o ecossistema Android e perfeita.\nO importante e começar. Crie um jogo simples, publique, e va evoluindo a partir daí. A melhor linguagem para gamedev e aquela que você domina e que te permite concluir seu projeto.\nPerguntas relacionadas Kotlin para desenvolvimento web Kotlin pode ser usado para iOS? Projetos Kotlin para iniciantes Melhor IDE para Kotlin Apps desktop com Kotlin ","permalink":"https://kotlin.dev.br/perguntas/kotlin-para-jogos/","summary":"\u003ch2 id=\"kotlin-pode-ser-usado-para-criar-jogos\"\u003eKotlin pode ser usado para criar jogos?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eSim, e possível criar jogos com Kotlin\u003c/strong\u003e, embora a linguagem não seja a escolha mais popular no mundo do desenvolvimento de jogos. Kotlin pode ser utilizada com algumas engines e frameworks específicos, além de ser viável para jogos Android nativos. Vamos explorar todas as opções, suas vantagens e limitações, para você decidir se faz sentido usar Kotlin no seu projeto de gamedev.\u003c/p\u003e\n\u003ch3 id=\"o-cenário-do-kotlin-no-desenvolvimento-de-jogos\"\u003eO cenário do Kotlin no desenvolvimento de jogos\u003c/h3\u003e\n\u003cp\u003eO desenvolvimento de jogos e historicamente dominado por linguagens como C++, C# (com Unity) e mais recentemente GDScript (com Godot). Kotlin não é a primeira linguagem que vem a mente quando se fala em gamedev, mas existem caminhos viáveis e interessantes para quem quer combinar seu conhecimento de Kotlin com a criação de jogos.\u003c/p\u003e","title":"Kotlin Pode Ser Usado para Criar Jogos? | Kotlin Brasil"},{"content":"Kotlin pode ser usado para desenvolvimento web? Sim, Kotlin pode ser usado tanto para backend quanto para frontend web. No backend, a linguagem já e amplamente utilizada com frameworks como Ktor e Spring Boot. No frontend, o Kotlin/JS permite compilar Kotlin para JavaScript, embora essa abordagem ainda seja menos popular. Vamos explorar cada cenário em detalhes.\nKotlin no backend web O uso mais consolidado de Kotlin na web e no desenvolvimento de APIs e serviços backend. Dois frameworks se destacam nessa area:\nKtor: o framework nativo de Kotlin\nCriado pela JetBrains, o Ktor é um framework leve, assíncrono e construido especificamente para Kotlin. Ele aproveita coroutines nativamente e é ideal para construir APIs REST, microsserviços e aplicações web.\nimport io.ktor.server.application.* import io.ktor.server.engine.* import io.ktor.server.netty.* import io.ktor.server.response.* import io.ktor.server.routing.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* fun main() { embeddedServer(Netty, port = 8080) { instalarPlugins() configurarRotas() }.start(wait = true) } fun Application.instalarPlugins() { install(ContentNegotiation) { json() } } fun Application.configurarRotas() { routing { route(\u0026#34;/api\u0026#34;) { get(\u0026#34;/produtos\u0026#34;) { val produtos = listOf( Produto(1, \u0026#34;Notebook\u0026#34;, 3500.00), Produto(2, \u0026#34;Mouse\u0026#34;, 89.90), Produto(3, \u0026#34;Teclado\u0026#34;, 199.90) ) call.respond(produtos) } get(\u0026#34;/produtos/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toLongOrNull() if (id != null) { call.respond(Produto(id, \u0026#34;Produto $id\u0026#34;, 99.90)) } else { call.respondText(\u0026#34;ID invalido\u0026#34;, status = io.ktor.http.HttpStatusCode.BadRequest) } } } } } @kotlinx.serialization.Serializable data class Produto(val id: Long, val nome: String, val preco: Double) Spring Boot com Kotlin\nSpring Boot e o framework Java mais popular do mundo, e tem suporte oficial e excelente para Kotlin. Muitas empresas brasileiras já usam Spring Boot com Kotlin em producao.\nimport org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication import org.springframework.web.bind.annotation.* @SpringBootApplication class AplicacaoWeb fun main(args: Array\u0026lt;String\u0026gt;) { runApplication\u0026lt;AplicacaoWeb\u0026gt;(*args) } @RestController @RequestMapping(\u0026#34;/api/tarefas\u0026#34;) class TarefaController(private val serviço: TarefaServico) { @GetMapping fun listar(): List\u0026lt;Tarefa\u0026gt; = serviço.listarTodas() @GetMapping(\u0026#34;/{id}\u0026#34;) fun buscar(@PathVariable id: Long): Tarefa = serviço.buscarPorId(id) ?: throw RecursoNaoEncontradoException(\u0026#34;Tarefa $id nao encontrada\u0026#34;) @PostMapping fun criar(@RequestBody tarefa: Tarefa): Tarefa = serviço.salvar(tarefa) @PutMapping(\u0026#34;/{id}\u0026#34;) fun atualizar(@PathVariable id: Long, @RequestBody tarefa: Tarefa): Tarefa = serviço.atualizar(id, tarefa) @DeleteMapping(\u0026#34;/{id}\u0026#34;) fun remover(@PathVariable id: Long) = serviço.remover(id) } data class Tarefa( val id: Long? = null, val titulo: String, val descricao: String, val concluida: Boolean = false ) Kotlin no frontend web Kotlin também pode ser usado no frontend web através do Kotlin/JS, que compila código Kotlin para JavaScript. Existem algumas abordagens disponiveis:\nKotlin/JS com wrappers para React\nA JetBrains mantém wrappers oficiais que permitem usar React com Kotlin:\n// Componente React escrito em Kotlin val App = FC\u0026lt;Props\u0026gt; { var contador by useState(0) div { h1 { +\u0026#34;Contador: $contador\u0026#34; } button { onClick = { contador++ } +\u0026#34;Incrementar\u0026#34; } button { onClick = { contador-- } +\u0026#34;Decrementar\u0026#34; } } } Kotlin/Wasm (experimental)\nUma fronteira ainda mais nova e o Kotlin/Wasm, que compila Kotlin para WebAssembly. Isso permite rodar código Kotlin diretamente no navegador com performance proxima a nativa.\nComparação entre frameworks web Kotlin Caracteristica Ktor Spring Boot Tamanho do framework Leve Robusto Curva de aprendizado Moderada Maior Ecossistema Crescente Enorme Performance Excelente Muito boa Comunidade Menor Enorme Ideal para Microsserviços, APIs Aplicações enterprise Vantagens de usar Kotlin para web Type safety: o sistema de tipos de Kotlin previne muitos erros em tempo de compilação Coroutines: tratamento elegante de programação assíncrona, essencial para servidores web Null safety: eliminacao de erros de NullPointerException que afetam aplicações em producao Ecossistema JVM: acesso a todas as bibliotecas Java existentes Produtividade: menos código boilerplate comparado com Java puro Full-stack Kotlin: possibilidade de usar a mesma linguagem no backend e frontend // Exemplo de coroutines no backend - tratamento assíncrono elegante suspend fun processarPedido(pedido: Pedido): Confirmacao { // Execucoes paralelas com coroutines return coroutineScope { val estoque = async { verificarEstoque(pedido.itens) } val pagamento = async { processarPagamento(pedido.valor) } val endereco = async { validarEndereco(pedido.enderecoEntrega) } // Aguarda todos os resultados Confirmacao( estoqueDisponivel = estoque.await(), pagamentoAprovado = pagamento.await(), enderecoValido = endereco.await() ) } } Desvantagens e limitações Frontend menos popular: para desenvolvimento frontend, JavaScript/TypeScript ainda dominam amplamente Menos vagas específicas de web: a maioria das vagas de Kotlin web são para backend Kotlin/JS ainda imaturo: o ecossistema frontend em Kotlin e limitado comparado com o de JavaScript Curva de aprendizado do ecossistema JVM: se você vem do mundo Node.js, pode estranhar o setup inicial Deploy mais pesado: aplicações JVM geralmente consomem mais memória que alternativas em Go ou Rust Banco de dados com Kotlin Um aspecto fundamental do desenvolvimento web backend e a integração com bancos de dados. Kotlin oferece várias opções excelentes:\n// Exposed - framework de banco de dados em Kotlin object Tarefas : Table(\u0026#34;tarefas\u0026#34;) { val id = long(\u0026#34;id\u0026#34;).autoIncrement() val titulo = varchar(\u0026#34;titulo\u0026#34;, 255) val concluida = bool(\u0026#34;concluida\u0026#34;).default(false) val criadoEm = datetime(\u0026#34;criado_em\u0026#34;).defaultExpression(CurrentDateTime) override val primaryKey = PrimaryKey(id) } // Consultas com DSL type-safe fun buscarTarefasPendentes(): List\u0026lt;Tarefa\u0026gt; { return transaction { Tarefas.select { Tarefas.concluida eq false } .orderBy(Tarefas.criadoEm) .map { row -\u0026gt; Tarefa( id = row[Tarefas.id], titulo = row[Tarefas.titulo], concluida = row[Tarefas.concluida] ) } } } Para quem Kotlin web e recomendado Equipes que já usam Kotlin no mobile e querem unificar a stack Projetos que precisam de alta performance e type safety no backend Empresas que usam Spring Boot em Java e querem migrar gradualmente Desenvolvedores que valorizam concisao e segurança de tipos Perguntas relacionadas Kotlin para backend Kotlin vale a pena em 2026? Melhor IDE para Kotlin E fácil encontrar emprego com Kotlin? Kotlin pode ser usado para iOS? ","permalink":"https://kotlin.dev.br/perguntas/kotlin-para-web/","summary":"\u003ch2 id=\"kotlin-pode-ser-usado-para-desenvolvimento-web\"\u003eKotlin pode ser usado para desenvolvimento web?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eSim, Kotlin pode ser usado tanto para backend quanto para frontend web.\u003c/strong\u003e No backend, a linguagem já e amplamente utilizada com frameworks como Ktor e Spring Boot. No frontend, o Kotlin/JS permite compilar Kotlin para JavaScript, embora essa abordagem ainda seja menos popular. Vamos explorar cada cenário em detalhes.\u003c/p\u003e\n\u003ch3 id=\"kotlin-no-backend-web\"\u003eKotlin no backend web\u003c/h3\u003e\n\u003cp\u003eO uso mais consolidado de Kotlin na web e no desenvolvimento de APIs e serviços backend. Dois frameworks se destacam nessa area:\u003c/p\u003e","title":"Kotlin Pode Ser Usado para Desenvolvimento Web? | Kotlin Brasil"},{"content":"Kotlin pode ser usado para desenvolver para iOS? Sim, Kotlin pode ser usado para desenvolvimento iOS através do Kotlin Multiplatform (KMP). Essa tecnologia permite compartilhar código Kotlin entre Android, iOS, desktop e web, mantendo a interface nativa de cada plataforma. Vamos explorar como isso funciona na prática, quais são as possibilidades e limitações, e se vale a pena investir nessa abordagem.\nO que é Kotlin Multiplatform? Kotlin Multiplatform é uma tecnologia desenvolvida pela JetBrains que permite escrever lógica de negocios em Kotlin e compartilha-la entre diferentes plataformas. Para iOS especificamente, o KMP compila o código Kotlin para binarios nativos usando o compilador Kotlin/Native, que gera frameworks que podem ser consumidos diretamente pelo Swift ou Objective-C.\nO ponto fundamental e que o KMP não substitui a UI nativa. No iOS, você continua usando SwiftUI ou UIKit para construir a interface. O que muda e que a lógica por tras da interface (regras de negócio, acesso a API, manipulação de dados) pode ser escrita uma única vez em Kotlin.\nComo funciona na prática Um projeto KMP tipico e organizado em modulos:\n// Modulo compartilhado (shared) - roda em Android e iOS // Definicao de uma interface expect/actual para funcionalidades de plataforma expect class Plataforma() { val nome: String } // Logica de negocios compartilhada class RepositorioUsuario(private val api: ApiServico) { suspend fun buscarUsuarios(): List\u0026lt;Usuario\u0026gt; { return api.obterUsuarios() .filter { it.ativo } .sortedBy { it.nome } } suspend fun buscarUsuarioPorId(id: Long): Resultado\u0026lt;Usuario\u0026gt; { return try { val usuario = api.obterUsuario(id) Resultado.Sucesso(usuario) } catch (e: Exception) { Resultado.Erro(\u0026#34;Falha ao buscar usuario: ${e.message}\u0026#34;) } } } // Modelo compartilhado data class Usuario( val id: Long, val nome: String, val email: String, val ativo: Boolean ) sealed class Resultado\u0026lt;out T\u0026gt; { data class Sucesso\u0026lt;T\u0026gt;(val dados: T) : Resultado\u0026lt;T\u0026gt;() data class Erro(val mensagem: String) : Resultado\u0026lt;Nothing\u0026gt;() } No lado iOS, o código Swift consome esse modulo compartilhado de forma natural:\n// Implementacao especifica para iOS (actual) actual class Plataforma actual constructor() { actual val nome: String = \u0026#34;iOS ${UIDevice.current.systemVersion}\u0026#34; } Bibliotecas multiplataforma essenciais O ecossistema KMP tem crescido rapidamente, e várias bibliotecas populares já oferecem suporte multiplataforma:\n// Ktor para chamadas HTTP multiplataforma class ApiServico { private val client = HttpClient { install(ContentNegotiation) { json(Json { prettyPrint = true isLenient = true ignoreUnknownKeys = true }) } } suspend fun obterUsuarios(): List\u0026lt;Usuario\u0026gt; { return client.get(\u0026#34;https://api.exemplo.com/usuarios\u0026#34;).body() } } // SQLDelight para banco de dados local multiplataforma // As queries SQL são compartilhadas entre plataformas // CREATE TABLE Usuario ( // id INTEGER PRIMARY KEY, // nome TEXT NOT NULL, // email TEXT NOT NULL // ); Principais bibliotecas multiplataforma:\nKtor: cliente HTTP SQLDelight: banco de dados local Koin: injeção de dependências Kotlinx.serialization: serialização JSON Kotlinx.coroutines: programação assíncrona Kotlinx.datetime: manipulação de datas Vantagens de usar Kotlin para iOS Compartilhamento de lógica: escrever regras de negócio uma única vez reduz bugs e inconsistencias entre plataformas Equipe unificada: desenvolvedores Kotlin podem contribuir para ambas as plataformas Kotlin/Native performatico: o código compilado roda com performance proxima ao nativo UI permanece nativa: a experiência do usuário não e comprometida, pois SwiftUI e UIKit continuam sendo usados Adoção gradual: você pode começar compartilhando apenas um modulo e expandir aos poucos Empresas de referência: Netflix, Cash App, Philips e VMware já usam KMP em producao Limitações e desafios Curva de aprendizado: configurar o ambiente e entender o sistema expect/actual leva tempo Necessidade de conhecer Swift: para a camada de UI, você ainda precisa de Swift ou Objective-C Mac obrigatório: para compilar para iOS, você precisa de um Mac com Xcode instalado Ecossistema ainda em amadurecimento: embora tenha crescido muito, nem todas as bibliotecas iOS tem equivalente KMP Debug entre plataformas: debugar problemas específicos do iOS em código Kotlin pode ser mais trabalhoso KMP vs outras abordagens multiplataforma KMP vs Flutter:\nKMP mantém a UI nativa; Flutter usa seu próprio motor de renderizacao KMP permite adoção gradual; Flutter exige reescrever toda a UI Flutter tem mais widgets prontos; KMP depende dos componentes nativos de cada plataforma KMP vs React Native:\nKMP compila para binario nativo; React Native usa uma ponte JavaScript KMP tem melhor performance; React Native pode ter gargalos na ponte React Native tem ecossistema mais maduro; KMP esta crescendo rapidamente Compose Multiplatform: o futuro da UI A JetBrains esta desenvolvendo o Compose Multiplatform, que leva o Jetpack Compose para além do Android. Com essa tecnologia, sera possível compartilhar não apenas a lógica, mas também a interface do usuário entre plataformas.\n// Compose Multiplatform - UI compartilhada (ainda em evolução para iOS) @Composable fun TelaListaUsuarios(viewModel: UsuarioViewModel) { val usuarios by viewModel.usuarios.collectAsState() LazyColumn { items(usuarios) { usuario -\u0026gt; CartaoUsuario(usuario) } } } @Composable fun CartaoUsuario(usuario: Usuario) { Card( modifier = Modifier .fillMaxWidth() .padding(8.dp) ) { Column(modifier = Modifier.padding(16.dp)) { Text(text = usuario.nome, style = MaterialTheme.typography.titleMedium) Text(text = usuario.email, style = MaterialTheme.typography.bodyMedium) } } } O Compose Multiplatform para iOS esta em fase de maturacao, mas já e funcional e promissor. Essa abordagem pode revolucionar o desenvolvimento multiplataforma nos próximos anos.\nVale a pena usar Kotlin para iOS? Sim, se:\nVocê já tem uma equipe que domina Kotlin Seu aplicativo tem lógica de negocios complexa que precisa ser consistente entre plataformas Você quer reduzir custos mantendo a qualidade nativa da UI Sua empresa esta disposta a investir na configuração inicial Talvez não, se:\nVocê precisa de um app exclusivamente para iOS (Swift puro seria mais direto) Sua equipe não tem experiência com Kotlin O app e muito simples e não justifica a complexidade adicional Perguntas relacionadas O que é Kotlin Multiplatform? Kotlin ou Flutter: qual escolher? Kotlin pode ser usado para web? Kotlin vale a pena em 2026? Apps desktop com Kotlin ","permalink":"https://kotlin.dev.br/perguntas/kotlin-para-ios/","summary":"\u003ch2 id=\"kotlin-pode-ser-usado-para-desenvolver-para-ios\"\u003eKotlin pode ser usado para desenvolver para iOS?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eSim, Kotlin pode ser usado para desenvolvimento iOS através do Kotlin Multiplatform (KMP)\u003c/strong\u003e. Essa tecnologia permite compartilhar código Kotlin entre Android, iOS, desktop e web, mantendo a interface nativa de cada plataforma. Vamos explorar como isso funciona na prática, quais são as possibilidades e limitações, e se vale a pena investir nessa abordagem.\u003c/p\u003e\n\u003ch3 id=\"o-que-é-kotlin-multiplatform\"\u003eO que é Kotlin Multiplatform?\u003c/h3\u003e\n\u003cp\u003eKotlin Multiplatform é uma tecnologia desenvolvida pela JetBrains que permite escrever lógica de negocios em Kotlin e compartilha-la entre diferentes plataformas. Para iOS especificamente, o KMP compila o código Kotlin para binarios nativos usando o compilador Kotlin/Native, que gera frameworks que podem ser consumidos diretamente pelo Swift ou Objective-C.\u003c/p\u003e","title":"Kotlin Pode Ser Usado para Desenvolver para iOS? | Kotlin Brasil"},{"content":"Quanto tempo leva para aprender Kotlin? Essa é uma pergunta que todo mundo faz antes de começar, é a resposta honesta e: depende. Depende da sua experiência previa, do tempo dedicado ao estudo e do nível que você quer atingir. Mas vamos ser mais específicos e tracar um cronograma realista para diferentes perfis de estudante.\nEstimativa por perfil Iniciante absoluto (nunca programou):\nBásico da linguagem: 2 a 3 meses Nível intermediário: 5 a 8 meses Nível profissional: 10 a 14 meses Programador de outra linguagem (Python, JavaScript, C#):\nBásico da linguagem: 2 a 4 semanas Nível intermediário: 2 a 3 meses Nível profissional: 4 a 6 meses Desenvolvedor Java:\nBásico da linguagem: 1 a 2 semanas Nível intermediário: 1 a 2 meses Nível profissional: 2 a 4 meses Esses tempos consideram um estudo diario de pelo menos uma hora. Se você puder dedicar mais tempo, os prazos diminuem proporcionalmente.\nFase 1: Fundamentos (2 a 6 semanas) Na primeira fase, você precisa dominar os conceitos básicos da linguagem. Isso inclui entender a sintaxe, os tipos de dados, o fluxo de controle e as funções.\n// Fundamentos que voce vai dominar na primeira fase fun main() { // Variaveis e tipos val nome: String = \u0026#34;Ana\u0026#34; var pontuacao = 0 // Condicionais como expressoes val nível = when { pontuacao \u0026gt;= 100 -\u0026gt; \u0026#34;Expert\u0026#34; pontuacao \u0026gt;= 50 -\u0026gt; \u0026#34;Intermediário\u0026#34; else -\u0026gt; \u0026#34;Iniciante\u0026#34; } // Funções com parametros padrao fun cumprimentar(pessoa: String, saudacao: String = \u0026#34;Ola\u0026#34;) { println(\u0026#34;$saudacao, $pessoa! Você esta no nível: $nível\u0026#34;) } cumprimentar(nome) cumprimentar(\u0026#34;Carlos\u0026#34;, \u0026#34;Bom dia\u0026#34;) // Coleções basicas val frutas = listOf(\u0026#34;Maca\u0026#34;, \u0026#34;Banana\u0026#34;, \u0026#34;Laranja\u0026#34;) frutas.forEachIndexed { i, fruta -\u0026gt; println(\u0026#34;${i + 1}. $fruta\u0026#34;) } } Topicos essenciais desta fase:\nVariaveis val e var Tipos básicos e inferencia de tipos Condicionais (if, when) Loops (for, while) Funções e parametros padrão Listas, mapas e conjuntos Null safety básico Fase 2: Orientacao a objetos e recursos intermediarios (4 a 8 semanas) Aqui você aprofunda nos conceitos de OOP aplicados ao Kotlin e começa a explorar recursos mais avançados da linguagem.\n// Conceitos intermediarios sealed interface Forma { fun area(): Double } data class Circulo(val raio: Double) : Forma { override fun area(): Double = Math.PI * raio * raio } data class Retangulo(val largura: Double, val altura: Double) : Forma { override fun area(): Double = largura * altura } // Função de extensao fun Double.formatarDecimais(casas: Int = 2): String = \u0026#34;%.${casas}f\u0026#34;.format(this) fun main() { val formas: List\u0026lt;Forma\u0026gt; = listOf( Circulo(5.0), Retangulo(3.0, 4.0), Circulo(2.5) ) formas.forEach { forma -\u0026gt; val tipo = forma::class.simpleName println(\u0026#34;$tipo: area = ${forma.area().formatarDecimais()} m2\u0026#34;) } // Operações com coleções val areaTotal = formas.sumOf { it.area() } val maiorForma = formas.maxByOrNull { it.area() } println(\u0026#34;Area total: ${areaTotal.formatarDecimais()} m2\u0026#34;) println(\u0026#34;Maior forma: ${maiorForma}\u0026#34;) } Topicos desta fase:\nClasses, heranca e interfaces Data classes e sealed classes Funções de extensao Lambdas e funções de ordem superior Operações avançadas com coleções Tratamento de exceções Generics básico Fase 3: Recursos avançados (4 a 8 semanas) Na terceira fase, você domina os recursos que diferenciam um desenvolvedor Kotlin junior de um pleno.\n// Coroutines - recurso avançado essencial import kotlinx.coroutines.* suspend fun buscarDados(url: String): String { delay(1000) // Simula chamada de rede return \u0026#34;Dados de $url\u0026#34; } fun main() = runBlocking { // Execução paralela com coroutines val resultado1 = async { buscarDados(\u0026#34;api/usuarios\u0026#34;) } val resultado2 = async { buscarDados(\u0026#34;api/produtos\u0026#34;) } println(resultado1.await()) println(resultado2.await()) // Flow para streams de dados val fluxo = flow { for (i in 1..5) { delay(500) emit(i) } } fluxo.collect { valor -\u0026gt; println(\u0026#34;Recebido: $valor\u0026#34;) } } Topicos desta fase:\nCoroutines e programação assíncrona Flow e StateFlow Generics avançado (variance, reified) DSLs em Kotlin Reflection e anotações Testes unitarios com JUnit e MockK Fase 4: Especializacao (tempo variavel) Depois de dominar a linguagem em si, você precisa se especializar em uma area. O tempo varia conforme a complexidade da area escolhida.\nAndroid com Jetpack Compose: 2 a 4 meses adicionais para se sentir confortavel com o ecossistema completo (navegação, persistencia, injeção de dependências).\nBackend com Ktor ou Spring Boot: 2 a 3 meses para entender o framework, banco de dados e deploy.\nKotlin Multiplatform: 3 a 4 meses para entender as especificidades de compartilhamento de código entre plataformas.\nPros e contras de cada ritmo de aprendizado Estudo intensivo (4+ horas por dia):\nPro: resultados rápidos e imersao profunda Pro: menos tempo até conseguir um emprego Contra: risco de burnout Contra: pode faltar tempo para absorver conceitos Estudo moderado (1-2 horas por dia):\nPro: sustentavel a longo prazo Pro: tempo para praticar e revisar Contra: progresso mais lento Contra: pode demorar para ver resultados práticos Estudo casual (algumas horas por semana):\nPro: não interfere na rotina Contra: progresso muito lento Contra: risco de esquecer o que aprendeu entre sessoes Aceleradores de aprendizado Algumas práticas podem reduzir significativamente o tempo necessário:\nProjetos práticos desde o inicio: não fique só na teoria. Crie algo real o mais rápido possível. Code review com outros desenvolvedores: ter alguem revisando seu código acelera a melhoria. Leitura de código open source: estudar projetos bem escritos ensina padrões e boas práticas. Participacao em comunidades: tire duvidas, ajude outros e troque experiencias. Consistencia acima de intensidade: melhor estudar 1 hora todo dia do que 10 horas uma vez por semana. Erro comum: achar que \u0026ldquo;aprender\u0026rdquo; tem um fim Um ponto importante e que aprender uma linguagem de programação não e um processo com um ponto final definido. Mesmo desenvolvedores seniors continuam aprendendo. O Kotlin evolui a cada versão, novos frameworks surgem, e novas práticas são adotadas pelo mercado.\nO objetivo não e \u0026ldquo;terminar de aprender Kotlin\u0026rdquo;, mas sim atingir um nível em que você consiga resolver problemas reais e continuar evoluindo a partir daí. Esse nível pode ser atingido em poucos meses com dedicacao e prática constante.\nPerguntas relacionadas Como aprender Kotlin em 2026? Kotlin e difícil de aprender? Como praticar Kotlin? Projetos Kotlin para iniciantes Precisa saber Java para aprender Kotlin? ","permalink":"https://kotlin.dev.br/perguntas/quanto-tempo-aprender-kotlin/","summary":"\u003ch2 id=\"quanto-tempo-leva-para-aprender-kotlin\"\u003eQuanto tempo leva para aprender Kotlin?\u003c/h2\u003e\n\u003cp\u003eEssa é uma pergunta que todo mundo faz antes de começar, é a resposta honesta e: \u003cstrong\u003edepende\u003c/strong\u003e. Depende da sua experiência previa, do tempo dedicado ao estudo e do nível que você quer atingir. Mas vamos ser mais específicos e tracar um cronograma realista para diferentes perfis de estudante.\u003c/p\u003e\n\u003ch3 id=\"estimativa-por-perfil\"\u003eEstimativa por perfil\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eIniciante absoluto (nunca programou):\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eBásico da linguagem: 2 a 3 meses\u003c/li\u003e\n\u003cli\u003eNível intermediário: 5 a 8 meses\u003c/li\u003e\n\u003cli\u003eNível profissional: 10 a 14 meses\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eProgramador de outra linguagem (Python, JavaScript, C#):\u003c/strong\u003e\u003c/p\u003e","title":"Quanto Tempo Leva para Aprender Kotlin? | Kotlin Brasil"},{"content":"E fácil encontrar emprego com Kotlin? O mercado de trabalho para desenvolvedores Kotlin tem crescido de forma consistente no Brasil e no mundo. A resposta curta e: sim, esta cada vez mais fácil encontrar vagas de Kotlin, especialmente se você tiver habilidades complementares. Mas vamos detalhar o cenário completo para você entender onde estao as oportunidades e como se preparar.\nO cenário do mercado de Kotlin no Brasil em 2026 O mercado brasileiro de tecnologia vive um momento favoravel para quem domina Kotlin. A linguagem se consolidou como a primeira escolha para desenvolvimento Android, e sua adoção em backend e multiplataforma tem acelerado. Grandes empresas como Nubank, iFood, Mercado Livre, PicPay e Itau já utilizam Kotlin extensivamente em seus projetos.\nAs vagas de Kotlin no Brasil se concentram principalmente em tres areas:\nDesenvolvimento Android: a maior fatia do mercado, com demanda constante por desenvolvedores que dominem Jetpack Compose e arquiteturas modernas Backend com Spring Boot ou Ktor: empresas que já usam a JVM estao migrando gradualmente de Java para Kotlin em novos serviços Kotlin Multiplatform: ainda emergente, mas com crescimento acelerado em empresas que querem compartilhar lógica entre plataformas Numeros que importam Embora os números exatos variem conforme a fonte, algumas tendências são claras:\nAs vagas de Kotlin para Android são abundantes em praticamente todas as plataformas de emprego brasileiras O salário médio de um desenvolvedor Kotlin no Brasil supera o de muitas outras linguagens Vagas remotas para empresas internacionais pagam em dolar, o que multiplica o poder de compra A relação entre vagas abertas e profissionais qualificados ainda favorece os candidatos Areas com mais oportunidades Android (maior demanda)\nO desenvolvimento Android e, de longe, a area com mais vagas para Kotlin. Praticamente toda empresa que desenvolve aplicativos para Android busca profissionais com experiência em Kotlin. O conhecimento de Jetpack Compose se tornou quase obrigatório em 2026.\n// Exemplo de Composable - habilidade essencial para vagas Android @Composable fun PerfilUsuario(nome: String, cargo: String) { Column( modifier = Modifier .fillMaxWidth() .padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Text( text = nome, style = MaterialTheme.typography.headlineMedium ) Spacer(modifier = Modifier.height(8.dp)) Text( text = cargo, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.secondary ) } } Backend (crescimento rápido)\nEmpresas que já usam Spring Boot em Java estao adotando Kotlin para novos microsservicos. Ktor, o framework web nativo de Kotlin, também tem ganhado espaco.\n// API simples com Ktor - habilidade valorizada no mercado fun Application.configurarRotas() { routing { get(\u0026#34;/api/status\u0026#34;) { call.respond( mapOf( \u0026#34;status\u0026#34; to \u0026#34;online\u0026#34;, \u0026#34;versao\u0026#34; to \u0026#34;1.0.0\u0026#34;, \u0026#34;timestamp\u0026#34; to System.currentTimeMillis() ) ) } get(\u0026#34;/api/usuarios/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toIntOrNull() if (id != null) { call.respond(buscarUsuario(id)) } else { call.respond(HttpStatusCode.BadRequest, \u0026#34;ID invalido\u0026#34;) } } } } Multiplataforma (emergente)\nKotlin Multiplatform esta crescendo e empresas como Netflix, Cash App e VMware já o utilizam. No Brasil, startups e empresas de médio porte estao comecando a adotar a tecnologia.\nPros e contras do mercado de Kotlin Vantagens:\nMenos concorrência por vaga comparado com Java ou JavaScript Salários geralmente acima da media do mercado Demanda crescente em todas as areas de atuacao Muitas vagas remotas disponiveis, inclusive internacionais O Google continua investindo pesado em Kotlin para Android Desvantagens:\nFora de Android, as vagas são menos numerosas que Java Algumas empresas menores no interior do Brasil ainda não adotaram Kotlin Para vagas de backend, muitas vezes pedem experiência em Java também O mercado de Kotlin Multiplatform ainda e pequeno no Brasil O que as empresas procuram em um desenvolvedor Kotlin Com base nas vagas publicadas no Brasil, as habilidades mais solicitadas são:\nKotlin idiomatico: saber usar os recursos da linguagem de forma elegante (null safety, coroutines, extensions, sealed classes) Arquitetura de software: MVVM, Clean Architecture, MVI Testes automatizados: JUnit, MockK, Espresso Ferramentas de build: Gradle com Kotlin DSL Versionamento: Git e fluxos de trabalho com branches // Exemplo de codigo idiomatico que demonstra dominio da linguagem sealed class Resultado\u0026lt;out T\u0026gt; { data class Sucesso\u0026lt;T\u0026gt;(val dados: T) : Resultado\u0026lt;T\u0026gt;() data class Erro(val mensagem: String) : Resultado\u0026lt;Nothing\u0026gt;() data object Carregando : Resultado\u0026lt;Nothing\u0026gt;() } fun \u0026lt;T\u0026gt; Resultado\u0026lt;T\u0026gt;.tratar( aoSucesso: (T) -\u0026gt; Unit, aoErro: (String) -\u0026gt; Unit = {}, aoCarregar: () -\u0026gt; Unit = {} ) { when (this) { is Resultado.Sucesso -\u0026gt; aoSucesso(dados) is Resultado.Erro -\u0026gt; aoErro(mensagem) is Resultado.Carregando -\u0026gt; aoCarregar() } } Dicas práticas para conseguir emprego com Kotlin 1. Construa um portfolio no GitHub\nEmpresas querem ver código. Crie projetos pessoais que demonstrem suas habilidades:\nUm app Android com Jetpack Compose usando uma API publica Um backend com Ktor ou Spring Boot Contribuicoes em projetos open source em Kotlin 2. Invista em certificacoes\nO Google oferece certificação em Android, que e altamente valorizada. Ter essa certificação no curriculo abre muitas portas.\n3. Participe da comunidade\nFrequente meetups, contribua em foruns, participe de hackatons. Networking e responsavel por uma parcela significativa das contratacoes em tecnologia no Brasil.\n4. Prepare-se para entrevistas tecnicas\nPratique problemas de algoritmos em Kotlin, estude padrões de projeto e esteja preparado para live coding. Muitas empresas pedem que você resolva problemas em tempo real durante a entrevista.\n5. Considere vagas remotas internacionais\nSe você domina ingles, o mercado internacional de Kotlin paga significativamente mais. Plataformas como LinkedIn, Wellfound e remote job boards publicam vagas remotas frequentemente.\nPerspectivas para o futuro O mercado de Kotlin tende a crescer ainda mais nos próximos anos. A JetBrains continua investindo pesado no desenvolvimento da linguagem, e o Google mantém Kotlin como prioridade para Android. A adoção em backend e multiplataforma só tende a aumentar, criando novas oportunidades para profissionais qualificados.\nO momento e favoravel para quem quer investir na linguagem. A demanda supera a oferta de profissionais, e essa tendencia deve continuar por um bom tempo.\nPerguntas relacionadas Salário de desenvolvedor Kotlin Kotlin vale a pena em 2026? Kotlin ou Java: qual aprender primeiro? Kotlin para backend Certificação Google em Kotlin ","permalink":"https://kotlin.dev.br/perguntas/kotlin-emprego-facil/","summary":"\u003ch2 id=\"e-fácil-encontrar-emprego-com-kotlin\"\u003eE fácil encontrar emprego com Kotlin?\u003c/h2\u003e\n\u003cp\u003eO mercado de trabalho para desenvolvedores Kotlin tem crescido de forma consistente no Brasil e no mundo. A resposta curta e: \u003cstrong\u003esim, esta cada vez mais fácil encontrar vagas de Kotlin\u003c/strong\u003e, especialmente se você tiver habilidades complementares. Mas vamos detalhar o cenário completo para você entender onde estao as oportunidades e como se preparar.\u003c/p\u003e\n\u003ch3 id=\"o-cenário-do-mercado-de-kotlin-no-brasil-em-2026\"\u003eO cenário do mercado de Kotlin no Brasil em 2026\u003c/h3\u003e\n\u003cp\u003eO mercado brasileiro de tecnologia vive um momento favoravel para quem domina Kotlin. A linguagem se consolidou como a primeira escolha para desenvolvimento Android, e sua adoção em backend e multiplataforma tem acelerado. Grandes empresas como Nubank, iFood, Mercado Livre, PicPay e Itau já utilizam Kotlin extensivamente em seus projetos.\u003c/p\u003e","title":"É Fácil Encontrar Emprego com Kotlin? | Kotlin Brasil"},{"content":"Precisa saber Java para aprender Kotlin? A resposta curta e: não, você não precisa saber Java para aprender Kotlin. Kotlin foi projetada para ser uma linguagem independente e completa, é muitos desenvolvedores ao redor do mundo comecam diretamente por ela. Mas vamos analisar essa questao com mais profundidade, porque existem nuances importantes que vale a pena entender.\nKotlin é uma linguagem autonoma Embora Kotlin rode na JVM (Java Virtual Machine) e seja interoperavel com Java, ela tem sua própria sintaxe, suas proprias convenções e seus próprios padrões. Você pode perfeitamente escrever projetos inteiros em Kotlin sem nunca tocar em uma linha de Java.\nA JetBrains, empresa criadora do Kotlin, sempre teve como objetivo criar uma linguagem que pudesse ser aprendida de forma independente. A documentação oficial do Kotlin não pressupoe conhecimento previo de Java, e os tutoriais comecam dos conceitos mais básicos.\n// Kotlin tem sua propria identidade sintatica fun main() { // Inferencia de tipos val linguagem = \u0026#34;Kotlin\u0026#34; val ano = 2026 // String templates nativos println(\u0026#34;Aprendendo $linguagem em $ano\u0026#34;) // Funções de extensao - conceito unico do Kotlin fun String.exclamar() = \u0026#34;$this!\u0026#34; println(linguagem.exclamar()) // \u0026#34;Kotlin!\u0026#34; } Quando saber Java ajuda Dito isso, conhecer Java pode ser útil em algumas situacoes específicas:\n1. Trabalhando com bibliotecas Java\nGrande parte do ecossistema de bibliotecas que você usara em projetos Kotlin foi originalmente escrita em Java. Saber ler código Java facilita quando você precisa consultar documentação ou debugar problemas.\n// Usando bibliotecas Java diretamente no Kotlin import java.time.LocalDate import java.time.format.DateTimeFormatter fun main() { // Classes Java funcionam naturalmente em Kotlin val hoje = LocalDate.now() val formatador = DateTimeFormatter.ofPattern(\u0026#34;dd/MM/yyyy\u0026#34;) println(\u0026#34;Data de hoje: ${hoje.format(formatador)}\u0026#34;) // Kotlin adiciona conveniencias sobre APIs Java val datas = listOf( LocalDate.of(2026, 1, 1), LocalDate.of(2026, 6, 15), LocalDate.of(2026, 12, 31) ) datas.filter { it.monthValue \u0026gt; 6 } .forEach { println(\u0026#34;Segundo semestre: ${it.format(formatador)}\u0026#34;) } } 2. Projetos mistos\nEm muitas empresas brasileiras, os projetos Android mais antigos tem código em Java e Kotlin coexistindo. Se você entrar em um time assim, vai precisar entender pelo menos o básico de Java.\n3. Entrevistas de emprego\nAlgumas empresas ainda incluem questões de Java nas entrevistas, mesmo para vagas de Kotlin. Ter pelo menos um entendimento superficial pode ser um diferencial.\nO que você precisa saber de verdade Em vez de Java, o que realmente importa antes de começar com Kotlin e ter uma base minima de lógica de programação. Conceitos como variaveis, condicionais, loops e funções são universais e aparecem em qualquer linguagem.\nSe você já entende esses conceitos básicos, consegue aprender Kotlin sem nenhum conhecimento previo de Java. Veja como esses conceitos aparecem em Kotlin:\n// Condicionais com expressoes fun classificarIdade(idade: Int): String = when { idade \u0026lt; 12 -\u0026gt; \u0026#34;Crianca\u0026#34; idade \u0026lt; 18 -\u0026gt; \u0026#34;Adolescente\u0026#34; idade \u0026lt; 60 -\u0026gt; \u0026#34;Adulto\u0026#34; else -\u0026gt; \u0026#34;Idoso\u0026#34; } // Loops com funcoes de colecao fun main() { val numeros = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // Filtrar pares e dobrar seus valores val resultado = numeros .filter { it % 2 == 0 } .map { it * 2 } println(\u0026#34;Resultado: $resultado\u0026#34;) // [4, 8, 12, 16, 20] // Classificacao de idades val idades = listOf(8, 15, 25, 45, 70) idades.forEach { idade -\u0026gt; println(\u0026#34;$idade anos: ${classificarIdade(idade)}\u0026#34;) } } Pros e contras de aprender Java antes do Kotlin Vantagens de já saber Java:\nFacilidade em entender o ecossistema JVM Leitura de documentação e código legado Valorizacao dos recursos exclusivos do Kotlin (você entende melhor por que eles existem) Mais facilidade em projetos mistos Java/Kotlin Desvantagens de exigir Java como pre-requisito:\nAtrasa desnecessariamente o inicio do aprendizado de Kotlin Java e mais verbosa, o que pode frustrar iniciantes Muitos conceitos de Java são desnecessários para quem só vai usar Kotlin O tempo gasto com Java poderia ser investido diretamente em Kotlin Conceitos da JVM que valem a pena entender Mesmo sem aprender Java como linguagem, alguns conceitos do ecossistema JVM são úteis para qualquer desenvolvedor Kotlin:\nComo a JVM funciona: entender que seu código Kotlin e compilado para bytecode que roda na JVM ajuda a compreender desempenho e compatibilidade Gerenciamento de memória: saber o básico sobre garbage collection e heap ajuda no desenvolvimento de aplicações performaticas Build tools: ferramentas como Gradle (que usa Kotlin DSL) são essenciais em projetos profissionais Estrutura de pacotes: a organizacao de código em pacotes segue as convenções do ecossistema Java // Entender pacotes e importante em qualquer projeto profissional package com.exemplo.meuprojeto.modelo data class Produto( val id: Long, val nome: String, val preco: Double ) { fun precoFormatado(): String = \u0026#34;R$ ${\u0026#34;%.2f\u0026#34;.format(preco)}\u0026#34; } Conselho prático para quem esta comecando Se você nunca programou antes, comece diretamente com Kotlin. A linguagem e amigavel para iniciantes e você pode aprender todos os conceitos fundamentais de programação usando ela.\nSe você já tem alguma experiência com outra linguagem (Python, JavaScript, C#), a transicao para Kotlin sera natural e você definitivamente não precisa passar por Java antes.\nSe você quer trabalhar especificamente com Android, comece com Kotlin e aprenda Jetpack Compose. O Google deixou claro que Kotlin e a linguagem do futuro para Android, e todo o material novo e focado nela.\nA única situação em que eu recomendaria estudar Java antes e se você já sabe que vai trabalhar em um projeto legado específico que usa Java extensivamente. Nesse caso, faz sentido conhecer ambas.\nCaminho recomendado Aprenda lógica de programação usando Kotlin Domine os fundamentos da linguagem (tipos, funções, classes, coleções) Escolha uma area de foco (Android, backend, multiplataforma) Quando se sentir confortavel, estude o básico de Java para ampliar suas possibilidades Continue evoluindo em ambas as linguagens conforme a demanda do mercado Perguntas relacionadas Kotlin ou Java: qual aprender primeiro? Kotlin e difícil de aprender? Como aprender Kotlin em 2026? Quanto tempo leva para aprender Kotlin? Kotlin vale a pena em 2026? ","permalink":"https://kotlin.dev.br/perguntas/kotlin-precisa-saber-java/","summary":"\u003ch2 id=\"precisa-saber-java-para-aprender-kotlin\"\u003ePrecisa saber Java para aprender Kotlin?\u003c/h2\u003e\n\u003cp\u003eA resposta curta e: \u003cstrong\u003enão, você não precisa saber Java para aprender Kotlin\u003c/strong\u003e. Kotlin foi projetada para ser uma linguagem independente e completa, é muitos desenvolvedores ao redor do mundo comecam diretamente por ela. Mas vamos analisar essa questao com mais profundidade, porque existem nuances importantes que vale a pena entender.\u003c/p\u003e\n\u003ch3 id=\"kotlin-é-uma-linguagem-autonoma\"\u003eKotlin é uma linguagem autonoma\u003c/h3\u003e\n\u003cp\u003eEmbora Kotlin rode na JVM (Java Virtual Machine) e seja interoperavel com Java, ela tem sua própria sintaxe, suas proprias convenções e seus próprios padrões. Você pode perfeitamente escrever projetos inteiros em Kotlin sem nunca tocar em uma linha de Java.\u003c/p\u003e","title":"Precisa Saber Java para Aprender Kotlin? | Kotlin Brasil"},{"content":"Kotlin ou Java: qual aprender primeiro? Essa é uma das perguntas mais frequentes entre quem esta dando os primeiros passos na programação. A resposta depende de vários fatores, como seus objetivos profissionais, o tipo de projeto que você quer desenvolver e até o tempo disponivel para estudo. Vamos analisar cada cenário com profundidade para você tomar a melhor decisao possível.\nO contexto histórico importa Java nasceu em 1995 e se consolidou como uma das linguagens mais populares do mundo. Durante mais de duas decadas, foi a escolha padrão para desenvolvimento Android, sistemas enterprise e aplicações backend de grande escala. Kotlin, por sua vez, foi criada pela JetBrains em 2011 e ganhou enorme tracao a partir de 2017, quando o Google a declarou linguagem oficial para Android.\nAmbas rodam na JVM (Java Virtual Machine), o que significa que compartilham o mesmo ecossistema de bibliotecas e ferramentas. Essa interoperabilidade é um dos maiores trunfos de quem decide aprender as duas linguagens.\nAprender Kotlin primeiro: vantagens Comecar por Kotlin tem se tornado cada vez mais popular, e não e por acaso. A linguagem foi projetada para resolver vários dos problemas historicos de Java, oferecendo uma sintaxe mais concisa e expressiva.\nVeja como fica a declaracao de variaveis e funções em Kotlin:\n// Declaracao de variaveis com inferencia de tipo val nome = \u0026#34;Maria\u0026#34; // imutavel var idade = 28 // mutavel // Função concisa fun saudacao(nome: String): String = \u0026#34;Ola, $nome!\u0026#34; // Data class que substitui dezenas de linhas em Java data class Desenvolvedor( val nome: String, val linguagem: String, val experiência: Int ) fun main() { val dev = Desenvolvedor(\u0026#34;Carlos\u0026#34;, \u0026#34;Kotlin\u0026#34;, 3) println(dev) // toString() automatico println(saudacao(dev.nome)) } As principais vantagens de começar por Kotlin incluem:\nNull safety nativa: o compilador impede erros de NullPointerException, um dos bugs mais comuns em Java Código mais enxuto: menos boilerplate significa que você foca no que realmente importa Coroutines: programação assíncrona de forma muito mais simples que threads tradicionais Curva de aprendizado moderna: a sintaxe e intuitiva e agradavel para iniciantes Aprender Java primeiro: vantagens Por outro lado, começar por Java também tem seus meritos. Como a linguagem e mais verbosa, ela obriga você a entender conceitos fundamentais de programação orientada a objetos de forma explicita.\nBase conceitual solida: você aprende OOP de forma detalhada e explicita Mercado de trabalho vasto: no Brasil, Java ainda lidera em número absoluto de vagas Documentação abundante: são mais de 25 anos de conteudo, tutoriais e livros disponiveis Sistemas legados: muitas empresas brasileiras ainda mantém grandes sistemas em Java Comparação prática: tratamento de nulos Um dos diferenciais mais significativos entre as duas linguagens e o tratamento de valores nulos. Veja a diferenca:\n// Em Kotlin, null safety e parte da linguagem fun buscarUsuario(id: Int): String? { // O ? indica que pode retornar null return if (id \u0026gt; 0) \u0026#34;Usuario $id\u0026#34; else null } fun main() { val usuario = buscarUsuario(1) // O compilador te obriga a tratar o null println(usuario?.uppercase() ?: \u0026#34;Usuario nao encontrado\u0026#34;) // Isso NAO compila - proteção contra NullPointerException // println(usuario.uppercase()) // Safe call com let usuario?.let { println(\u0026#34;Encontrado: $it\u0026#34;) } } Em Java, você precisaria de verificacoes manuais de null ou usar Optional, o que adiciona complexidade ao código.\nAnálise de cenários: qual escolher? Cenario 1 - Você quer desenvolver apps Android: Kotlin, sem duvida. O Google recomenda Kotlin como linguagem principal desde 2019, e o Jetpack Compose, o framework moderno de UI, e escrito inteiramente em Kotlin.\nCenario 2 - Você quer trabalhar com backend enterprise: Java ainda domina nesse segmento no Brasil, mas Kotlin esta crescendo rapidamente com frameworks como Ktor e Spring Boot (que tem suporte excelente a Kotlin).\nCenario 3 - Você e totalmente iniciante em programação: Kotlin pode ser mais amigavel por exigir menos código para fazer as mesmas coisas, o que reduz a frustracao inicial.\nCenario 4 - Você quer maximizar suas chances de emprego imediato: Java tem mais vagas no total, mas as vagas de Kotlin costumam pagar melhor e ter menos concorrência.\nPros e contras resumidos Aprender Kotlin primeiro:\nPro: sintaxe moderna e produtiva Pro: null safety evita erros comuns desde o inicio Pro: linguagem oficial do Android Contra: menos material em português comparado com Java Contra: algumas empresas ainda pedem Java no processo seletivo Aprender Java primeiro:\nPro: base conceitual mais explicita Pro: mais vagas e conteudo disponivel Pro: facilita a transicao para Kotlin depois Contra: mais verboso e propenso a erros com null Contra: não acompanha tendências modernas tao rapidamente Conselho prático A minha recomendacao sincera e: comece por Kotlin se você quer produtividade rápida, e por Java se você quer construir uma base teorica mais robusta. De qualquer forma, profissionais que dominam ambas são extremamente valorizados no mercado brasileiro.\nSe você tem pressa para entrar no mercado de trabalho e quer focar em mobile, va de Kotlin. Se pretende trabalhar em grandes corporacoes com sistemas legados, Java e mais seguro. O ideal, claro, e aprender as duas ao longo do tempo, já que a interoperabilidade entre elas e perfeita.\nUma estrategia que funciona muito bem e começar com Kotlin, ganhar confianca e produtividade, e depois estudar Java para entender o que acontece \u0026ldquo;por baixo dos panos\u0026rdquo;. Assim você tem o melhor dos dois mundos.\nDicas para começar hoje Acesse o Kotlin Playground e teste código sem instalar nada Faca os exercícios do Kotlin Koans no site oficial Escolha um projeto pessoal simples e implemente em ambas as linguagens Participe de comunidades brasileiras de Kotlin e Java para trocar experiencias Nao se prenda a uma única linguagem: a flexibilidade e o maior ativo de um desenvolvedor Perguntas relacionadas Kotlin ou Java: qual escolher? Precisa saber Java para aprender Kotlin? Kotlin vale a pena em 2026? Como aprender Kotlin em 2026? Quanto tempo leva para aprender Kotlin? ","permalink":"https://kotlin.dev.br/perguntas/kotlin-vs-java-qual-aprender/","summary":"\u003ch2 id=\"kotlin-ou-java-qual-aprender-primeiro\"\u003eKotlin ou Java: qual aprender primeiro?\u003c/h2\u003e\n\u003cp\u003eEssa é uma das perguntas mais frequentes entre quem esta dando os primeiros passos na programação. A resposta depende de vários fatores, como seus objetivos profissionais, o tipo de projeto que você quer desenvolver e até o tempo disponivel para estudo. Vamos analisar cada cenário com profundidade para você tomar a melhor decisao possível.\u003c/p\u003e\n\u003ch3 id=\"o-contexto-histórico-importa\"\u003eO contexto histórico importa\u003c/h3\u003e\n\u003cp\u003eJava nasceu em 1995 e se consolidou como uma das linguagens mais populares do mundo. Durante mais de duas decadas, foi a escolha padrão para desenvolvimento Android, sistemas enterprise e aplicações backend de grande escala. Kotlin, por sua vez, foi criada pela JetBrains em 2011 e ganhou enorme tracao a partir de 2017, quando o Google a declarou linguagem oficial para Android.\u003c/p\u003e","title":"Kotlin ou Java: Qual Aprender Primeiro? | Kotlin Brasil"},{"content":"Kotlin/Native vs JNI: integração com código nativo em 2026 Integrar código nativo (C, C++, Rust) com Kotlin e necessário em diversos cenários: bibliotecas de criptografia, processamento de imagem, SDKs legados e acesso a APIs do sistema operacional. As duas principais abordagens são Kotlin/Native (com cinterop) e JNI (Java Native Interface) no Kotlin/JVM. Este artigo compara ambas em profundidade.\nVisao geral Caracteristica Kotlin/Native (cinterop) JNI (Kotlin/JVM) Plataforma Kotlin/Native (iOS, Linux, macOS, Windows) JVM (Android, Server) Interop Direto com C (cinterop) Bridge Java-Nativo Overhead de chamada Minimo (sem bridge) Moderado (JNI bridge) Gerenciamento de memória Kotlin GC + manual C JVM GC + manual C Segurança de tipos Boa (bindings gerados) Limitada (signatures manuais) Boilerplate Baixo Alto Debugging Moderado Dificil Maturidade Estavel Muito maduro Como funciona cada abordagem Kotlin/Native com cinterop Kotlin/Native compila Kotlin para código nativo (sem JVM). A ferramenta cinterop gera bindings Kotlin automaticamente a partir de headers C, permitindo chamar funções C diretamente:\n// Arquivo de definicao: src/nativeInterop/cinterop/openssl.def headers = openssl/sha.h headerFilter = openssl/** linkerOpts.linux = -lssl -lcrypto linkerOpts.macos = -lssl -lcrypto Com essa definicao, o compilador gera bindings Kotlin automaticamente:\n// Uso em Kotlin/Native - bindings gerados automaticamente import kotlinx.cinterop.* import openssl.* fun calcularSHA256(dados: String): String { val input = dados.encodeToByteArray() val hash = ByteArray(SHA256_DIGEST_LENGTH) memScoped { val inputPtr = input.refTo(0).getPointer(this) val hashPtr = hash.refTo(0).getPointer(this) SHA256(inputPtr.reinterpret(), input.size.toULong(), hashPtr.reinterpret()) } return hash.joinToString(\u0026#34;\u0026#34;) { \u0026#34;%02x\u0026#34;.format(it) } } fun main() { val hash = calcularSHA256(\u0026#34;Kotlin Brasil\u0026#34;) println(\u0026#34;SHA256: $hash\u0026#34;) } O cinterop também suporta structs, callbacks, ponteiros e enums de C:\n// Interop com structs C fun obterInfoSistema(): String { memScoped { val info = alloc\u0026lt;utsname\u0026gt;() uname(info.ptr) return \u0026#34;Sistema: ${info.sysname.toKString()}, \u0026#34; + \u0026#34;Maquina: ${info.machine.toKString()}\u0026#34; } } // Callbacks de C para Kotlin fun registrarCallback() { val callback = staticCFunction\u0026lt;Int, Int\u0026gt; { sinal -\u0026gt; println(\u0026#34;Sinal recebido: $sinal\u0026#34;) 0 } signal(SIGINT, callback) } JNI com Kotlin/JVM JNI e a interface padrão da JVM para chamar código nativo. Requer criar headers, implementar funções em C/C++ e carregar a biblioteca compartilhada:\n// Kotlin/JVM: declaracao dos metodos nativos class CryptoNativo { companion object { init { System.loadLibrary(\u0026#34;crypto_nativo\u0026#34;) } } external fun calcularSHA256(dados: ByteArray): ByteArray external fun criptografarAES(dados: ByteArray, chave: ByteArray): ByteArray external fun descriptografarAES(dados: ByteArray, chave: ByteArray): ByteArray } // Implementacao em C (crypto_nativo.c) #include \u0026lt;jni.h\u0026gt; #include \u0026lt;openssl/sha.h\u0026gt; #include \u0026lt;string.h\u0026gt; JNIEXPORT jbyteArray JNICALL Java_CryptoNativo_calcularSHA256(JNIEnv *env, jobject obj, jbyteArray dados) { jsize tamanho = (*env)-\u0026gt;GetArrayLength(env, dados); jbyte *input = (*env)-\u0026gt;GetByteArrayElements(env, dados, NULL); unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256((unsigned char *)input, tamanho, hash); (*env)-\u0026gt;ReleaseByteArrayElements(env, dados, input, JNI_ABORT); jbyteArray resultado = (*env)-\u0026gt;NewByteArray(env, SHA256_DIGEST_LENGTH); (*env)-\u0026gt;SetByteArrayRegion(env, resultado, 0, SHA256_DIGEST_LENGTH, (jbyte *)hash); return resultado; } // Uso em Kotlin fun main() { val crypto = CryptoNativo() val dados = \u0026#34;Kotlin Brasil\u0026#34;.encodeToByteArray() val hash = crypto.calcularSHA256(dados) println(\u0026#34;SHA256: ${hash.joinToString(\u0026#34;\u0026#34;) { \u0026#34;%02x\u0026#34;.format(it) }}\u0026#34;) } Comparação de boilerplate A diferenca no volume de código necessário e significativa. Para chamar uma função C simples:\nKotlin/Native: 3 passos Criar arquivo .def com os headers Configurar no build.gradle.kts Chamar a função diretamente em Kotlin // build.gradle.kts kotlin { linuxX64 { compilations.getByName(\u0026#34;main\u0026#34;) { cinterops { val openssl by creating { defFile(project.file(\u0026#34;src/nativeInterop/cinterop/openssl.def\u0026#34;)) } } } } } JNI: 6 passos Declarar método external em Kotlin Compilar a classe para gerar header JNI (javac -h) Implementar a função em C/C++ com assinatura JNI Compilar a biblioteca nativa (.só/.dylib/.dll) Colocar a biblioteca no path correto Carregar com System.loadLibrary() O JNI exige manter sincronia entre a assinatura Kotlin e a implementação C. Se você renomear um método ou mudar o pacote, precisa atualizar o header C manualmente.\nPerformance Operação Kotlin/Native JNI Chamada de função simples ~1-5ns ~50-100ns Passagem de array pequeno ~10ns ~200-500ns (copia) Passagem de array grande ~100ns (ponteiro) ~1-10ms (copia JNI) Callback nativo -\u0026gt; Kotlin ~5-10ns ~100-500ns Alocacao de memória malloc direto JNI NewByteArray A principal diferenca de performance esta no overhead da bridge JNI. Cada chamada JNI envolve: verificação de thread, lookup de método, conversao de tipos e potencialmente copia de dados. Kotlin/Native chama funções C diretamente sem intermediarios.\nPara chamadas esporadicas (inicialização, operações de rede), o overhead JNI e irrelevante. Para chamadas em loop apertado (processamento de audio/video frame a frame), a diferenca pode ser significativa.\nGerenciamento de memória Kotlin/Native Kotlin/Native usa seu próprio garbage collector e fornece memScoped para gerenciar memória nativa:\nfun processarDados(tamanho: Int): List\u0026lt;Double\u0026gt; { return memScoped { val buffer = allocArray\u0026lt;DoubleVar\u0026gt;(tamanho) // Preencher buffer com dados de C preencher_buffer(buffer, tamanho) // Converter para lista Kotlin (copia os dados) (0 until tamanho).map { buffer[it] } } // memoria nativa liberada automaticamente aqui } O memScoped funciona como um bloco try-with-resources: toda memória alocada dentro dele e liberada ao sair do escopo. Isso previne vazamentos de memória nativos de forma elegante.\nJNI JNI requer cuidado manual com referências e copias:\nJNIEXPORT jobject JNICALL Java_Processador_processar(JNIEnv *env, jobject obj, jint tamanho) { double *buffer = (double *)malloc(tamanho * sizeof(double)); if (!buffer) return NULL; preencher_buffer(buffer, tamanho); // Criar ArrayList Java jclass listClass = (*env)-\u0026gt;FindClass(env, \u0026#34;java/util/ArrayList\u0026#34;); jmethodID listInit = (*env)-\u0026gt;GetMethodID(env, listClass, \u0026#34;\u0026lt;init\u0026gt;\u0026#34;, \u0026#34;(I)V\u0026#34;); jmethodID listAdd = (*env)-\u0026gt;GetMethodID(env, listClass, \u0026#34;add\u0026#34;, \u0026#34;(Ljava/lang/Object;)Z\u0026#34;); jobject lista = (*env)-\u0026gt;NewObject(env, listClass, listInit, tamanho); jclass doubleClass = (*env)-\u0026gt;FindClass(env, \u0026#34;java/lang/Double\u0026#34;); jmethodID doubleInit = (*env)-\u0026gt;GetMethodID(env, doubleClass, \u0026#34;\u0026lt;init\u0026gt;\u0026#34;, \u0026#34;(D)V\u0026#34;); for (int i = 0; i \u0026lt; tamanho; i++) { jobject valor = (*env)-\u0026gt;NewObject(env, doubleClass, doubleInit, buffer[i]); (*env)-\u0026gt;CallBooleanMethod(env, lista, listAdd, valor); (*env)-\u0026gt;DeleteLocalRef(env, valor); // prevenir leak de referência local } free(buffer); // nao esquecer! return lista; } O código JNI e significativamente mais verboso e propenso a erros. Esquecer de chamar DeleteLocalRef ou free causa vazamentos.\nSegurança e debugging Kotlin/Native Os bindings gerados pelo cinterop preservam tipos C em tipos Kotlin equivalentes. Ponteiros são representados como CPointer\u0026lt;T\u0026gt;, o que oferece alguma segurança de tipos. Porem, operações com ponteiros continuam sendo inseguras por natureza.\nO debugging e feito com ferramentas como LLDB e o debugger do IntelliJ IDEA, que suporta step-through entre código Kotlin e código C.\nJNI JNI não oferece verificação de tipos na fronteira Java-Nativo. A assinatura da função C usa um formato textual (\u0026quot;(Ljava/lang/Object;)Z\u0026quot;) que não e verificado em tempo de compilação. Erros de assinatura causam crashes em runtime.\nO debugging de JNI e notoriamente difícil. Você precisa configurar debugger nativo e Java simultaneamente, e crashes no lado nativo frequentemente produzem stack traces pouco informativas.\nCasos de uso práticos Kotlin/Native e ideal para: Aplicações Kotlin Multiplatform que precisam de interop com C no iOS ou Desktop CLI tools compiladas nativamente Bibliotecas que precisam funcionar sem JVM Projetos que acessam APIs de sistema operacional (POSIX, Win32) Integração com SDKs nativos no iOS (Objective-C/Swift via cinterop) JNI e ideal para: Aplicações Android que precisam de NDK (OpenGL, processamento de camera) Servidores Kotlin/JVM que usam bibliotecas C de alta performance reutilização de bibliotecas nativas existentes em projetos JVM Projetos que já tem investimento significativo em código JNI Alternativas modernas Para projetos JVM, alternativas ao JNI estao ganhando tracao:\nJNA (Java Native Access): não requer código C de bridge, mas e mais lento que JNI.\nProject Panama (Foreign Function \u0026amp; Memory API): API moderna do Java 22+ que substitui JNI com uma interface mais segura e performante. Kotlin pode usar diretamente.\n// Panama FFI (Java 22+) import java.lang.foreign.* fun chamarFuncaoC() { val linker = Linker.nativeLinker() val lookup = SymbolLookup.loaderLookup() val strlen = linker.downcallHandle( lookup.find(\u0026#34;strlen\u0026#34;).orElseThrow(), FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS) ) Arena.ofConfined().use { arena -\u0026gt; val str = arena.allocateFrom(\u0026#34;Kotlin Brasil\u0026#34;) val tamanho = strlen.invoke(str) as Long println(\u0026#34;Tamanho: $tamanho\u0026#34;) } } Veredito A escolha entre Kotlin/Native e JNI depende da plataforma alvo. Se você desenvolve para iOS, Desktop ou Linux com Kotlin Multiplatform, Kotlin/Native com cinterop e a escolha natural: menos boilerplate, melhor performance de chamada e gerenciamento de memória mais seguro. Se você esta no ecossistema JVM (Android NDK ou servidor), JNI e a opção estabelecida, embora verbose. Em 2026, considere também o Project Panama como alternativa moderna ao JNI para projetos que rodam em Java 22+. Para interoperabilidade nativa com C, Rust oferece FFI seguro com zero-cost abstractions, e Zig se destaca pela compatibilidade direta com headers C. Independentemente da escolha, integração com código nativo requer cuidado com gerenciamento de memória e segurança de ponteiros.\n","permalink":"https://kotlin.dev.br/comparacoes/kotlin-native-vs-jni/","summary":"\u003ch2 id=\"kotlinnative-vs-jni-integração-com-código-nativo-em-2026\"\u003eKotlin/Native vs JNI: integração com código nativo em 2026\u003c/h2\u003e\n\u003cp\u003eIntegrar código nativo (C, C++, Rust) com Kotlin e necessário em diversos cenários: bibliotecas de criptografia, processamento de imagem, SDKs legados e acesso a APIs do sistema operacional. As duas principais abordagens são Kotlin/Native (com cinterop) e JNI (Java Native Interface) no Kotlin/JVM. Este artigo compara ambas em profundidade.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracteristica\u003c/th\u003e\n          \u003cth\u003eKotlin/Native (cinterop)\u003c/th\u003e\n          \u003cth\u003eJNI (Kotlin/JVM)\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePlataforma\u003c/td\u003e\n          \u003ctd\u003eKotlin/Native (iOS, Linux, macOS, Windows)\u003c/td\u003e\n          \u003ctd\u003eJVM (Android, Server)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eInterop\u003c/td\u003e\n          \u003ctd\u003eDireto com C (cinterop)\u003c/td\u003e\n          \u003ctd\u003eBridge Java-Nativo\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eOverhead de chamada\u003c/td\u003e\n          \u003ctd\u003eMinimo (sem bridge)\u003c/td\u003e\n          \u003ctd\u003eModerado (JNI bridge)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eGerenciamento de memória\u003c/td\u003e\n          \u003ctd\u003eKotlin GC + manual C\u003c/td\u003e\n          \u003ctd\u003eJVM GC + manual C\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSegurança de tipos\u003c/td\u003e\n          \u003ctd\u003eBoa (bindings gerados)\u003c/td\u003e\n          \u003ctd\u003eLimitada (signatures manuais)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eBoilerplate\u003c/td\u003e\n          \u003ctd\u003eBaixo\u003c/td\u003e\n          \u003ctd\u003eAlto\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDebugging\u003c/td\u003e\n          \u003ctd\u003eModerado\u003c/td\u003e\n          \u003ctd\u003eDificil\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eMaturidade\u003c/td\u003e\n          \u003ctd\u003eEstavel\u003c/td\u003e\n          \u003ctd\u003eMuito maduro\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"como-funciona-cada-abordagem\"\u003eComo funciona cada abordagem\u003c/h2\u003e\n\u003ch3 id=\"kotlinnative-com-cinterop\"\u003eKotlin/Native com cinterop\u003c/h3\u003e\n\u003cp\u003eKotlin/Native compila Kotlin para código nativo (sem JVM). A ferramenta cinterop gera bindings Kotlin automaticamente a partir de headers C, permitindo chamar funções C diretamente:\u003c/p\u003e","title":"Kotlin/Native vs JNI: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Gradle Kotlin DSL vs Groovy DSL: configuração de build em 2026 O Gradle suporta dois DSLs para configuração de build: Groovy (histórico, arquivos .gradle) e Kotlin (moderno, arquivos .gradle.kts). Em 2026, o Kotlin DSL é a escolha padrão para novos projetos, mas muitos projetos legados ainda usam Groovy. Este artigo compara as duas opções em detalhes práticos.\nVisao geral Caracteristica Kotlin DSL (.gradle.kts) Groovy DSL (.gradle) Extensao .gradle.kts .gradle Tipagem Estática Dinamica Autocompletar IDE Completo Limitado Navegação ao código fonte Sim Parcial Documentação inline Sim (KDoc) Limitada Refatoração Suportada Limitada Performance de compilação Mais lenta (primeiro build) Mais rápida Cache de scripts Eficiente (apos primeiro build) Eficiente Padrao novos projetos Sim (desde Gradle 8+) Legado Sintaxe comparada Configuração básica do projeto Kotlin DSL:\n// build.gradle.kts plugins { id(\u0026#34;org.jetbrains.kotlin.jvm\u0026#34;) version \u0026#34;2.1.0\u0026#34; id(\u0026#34;application\u0026#34;) } group = \u0026#34;com.exemplo\u0026#34; version = \u0026#34;1.0.0\u0026#34; repositories { mavenCentral() } dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-core:3.0.0\u0026#34;) testImplementation(\u0026#34;io.kotest:kotest-runner-junit5:5.9.0\u0026#34;) } application { mainClass.set(\u0026#34;com.exemplo.MainKt\u0026#34;) } tasks.test { useJUnitPlatform() } Groovy DSL:\n// build.gradle plugins { id \u0026#39;org.jetbrains.kotlin.jvm\u0026#39; version \u0026#39;2.1.0\u0026#39; id \u0026#39;application\u0026#39; } group = \u0026#39;com.exemplo\u0026#39; version = \u0026#39;1.0.0\u0026#39; repositories { mavenCentral() } dependencies { implementation \u0026#39;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0\u0026#39; implementation \u0026#39;io.ktor:ktor-server-core:3.0.0\u0026#39; testImplementation \u0026#39;io.kotest:kotest-runner-junit5:5.9.0\u0026#39; } application { mainClass = \u0026#39;com.exemplo.MainKt\u0026#39; } test { useJUnitPlatform() } As diferenças visuais são sutis: Kotlin usa parenteses e aspas duplas consistentemente, enquanto Groovy permite aspas simples e omissao de parenteses.\nConfiguração Android Kotlin DSL:\n// build.gradle.kts (modulo app) plugins { id(\u0026#34;com.android.application\u0026#34;) id(\u0026#34;org.jetbrains.kotlin.android\u0026#34;) id(\u0026#34;org.jetbrains.kotlin.plugin.compose\u0026#34;) } android { namespace = \u0026#34;com.exemplo.app\u0026#34; compileSdk = 35 defaultConfig { applicationId = \u0026#34;com.exemplo.app\u0026#34; minSdk = 24 targetSdk = 35 versionCode = 1 versionName = \u0026#34;1.0.0\u0026#34; } buildTypes { release { isMinifyEnabled = true proguardFiles( getDefaultProguardFile(\u0026#34;proguard-android-optimize.txt\u0026#34;), \u0026#34;proguard-rules.pro\u0026#34; ) } debug { isMinifyEnabled = false applicationIdSuffix = \u0026#34;.debug\u0026#34; } } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } } dependencies { implementation(libs.androidx.core.ktx) implementation(libs.androidx.compose.ui) implementation(libs.androidx.compose.material3) debugImplementation(libs.androidx.compose.ui.tooling) } Groovy DSL:\n// build.gradle (modulo app) plugins { id \u0026#39;com.android.application\u0026#39; id \u0026#39;org.jetbrains.kotlin.android\u0026#39; id \u0026#39;org.jetbrains.kotlin.plugin.compose\u0026#39; } android { namespace \u0026#39;com.exemplo.app\u0026#39; compileSdk 35 defaultConfig { applicationId \u0026#39;com.exemplo.app\u0026#39; minSdk 24 targetSdk 35 versionCode 1 versionName \u0026#39;1.0.0\u0026#39; } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile(\u0026#39;proguard-android-optimize.txt\u0026#39;), \u0026#39;proguard-rules.pro\u0026#39; } debug { minifyEnabled false applicationIdSuffix \u0026#39;.debug\u0026#39; } } compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } } dependencies { implementation libs.androidx.core.ktx implementation libs.androidx.compose.ui implementation libs.androidx.compose.material3 debugImplementation libs.androidx.compose.ui.tooling } Autocompletar e suporte da IDE A maior vantagem prática do Kotlin DSL e o suporte completo da IDE. No IntelliJ IDEA e Android Studio:\nKotlin DSL oferece:\nAutocompletar completo para todas as propriedades e métodos do Gradle Navegação ao código fonte de plugins e extensoes (Ctrl+Click) verificação de erros em tempo real (sublinhado vermelho para erros) Refatoração automatica (renomear, mover) Documentação inline ao passar o mouse sobre propriedades Groovy DSL oferece:\nAutocompletar básico (menos confiavel) Navegação limitada ao código fonte verificação de erros minima (muitos erros só aparecem no build) Refatoração limitada Na prática, essa diferenca e enorme. Com Groovy, você frequentemente consulta documentação externa para saber quais propriedades estao disponiveis. Com Kotlin DSL, a IDE mostra tudo diretamente.\nSegurança de tipos Kotlin DSL verifica tipos em tempo de compilação do script:\n// Kotlin DSL: erro detectado pela IDE android { compileSdk = \u0026#34;35\u0026#34; // ERRO: esperado Int, recebido String minSdk = 24 // OK } // Groovy DSL: compila sem erro, falha em runtime android { compileSdk = \u0026#34;35\u0026#34; // Nenhum erro no editor, falha no build minSdk = 24 } Essa segurança previne erros comuns como atribuir tipos errados, usar nomes de propriedade inexistentes ou chamar métodos com parametros incorretos.\nPerformance de build A performance de compilação dos scripts e frequentemente citada como desvantagem do Kotlin DSL:\nCenario Kotlin DSL Groovy DSL Primeiro build (cold) Mais lento (~20-30% mais) Mais rápido Builds subsequentes (cache) Equivalente Equivalente Mudanca no script Re-compila script Re-interpreta script Sync do projeto na IDE Mais lento inicialmente Mais rápido Na prática, a diferenca e perceptivel apenas no primeiro build ou apos alterar scripts de build. Para builds incrementais do código da aplicação (o cenário mais frequente), não há diferenca.\nVersion Catalogs Ambos os DSLs suportam Version Catalogs (arquivo libs.versions.toml), que e a abordagem recomendada para gerenciar versões de dependências:\n# gradle/libs.versions.toml [versions] kotlin = \u0026#34;2.1.0\u0026#34; ktor = \u0026#34;3.0.0\u0026#34; coroutines = \u0026#34;1.9.0\u0026#34; kotest = \u0026#34;5.9.0\u0026#34; [libraries] ktor-server-core = { module = \u0026#34;io.ktor:ktor-server-core\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } ktor-server-netty = { module = \u0026#34;io.ktor:ktor-server-netty\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } coroutines-core = { module = \u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core\u0026#34;, version.ref = \u0026#34;coroutines\u0026#34; } kotest-runner = { module = \u0026#34;io.kotest:kotest-runner-junit5\u0026#34;, version.ref = \u0026#34;kotest\u0026#34; } [plugins] kotlin-jvm = { id = \u0026#34;org.jetbrains.kotlin.jvm\u0026#34;, version.ref = \u0026#34;kotlin\u0026#34; } // Kotlin DSL com version catalog plugins { alias(libs.plugins.kotlin.jvm) } dependencies { implementation(libs.ktor.server.core) implementation(libs.coroutines.core) testImplementation(libs.kotest.runner) } Com version catalogs, o Kotlin DSL oferece autocompletar para libs. que mostra todas as dependências disponiveis. Groovy também suporta, mas sem o mesmo nível de integração IDE.\nConvention Plugins Para projetos multi-modulo, convention plugins permitem compartilhar configuração entre modulos. O Kotlin DSL brilha aqui:\n// buildSrc/src/main/kotlin/kotlin-library-conventions.gradle.kts plugins { id(\u0026#34;org.jetbrains.kotlin.jvm\u0026#34;) } group = \u0026#34;com.exemplo\u0026#34; repositories { mavenCentral() } dependencies { testImplementation(\u0026#34;io.kotest:kotest-runner-junit5:5.9.0\u0026#34;) } tasks.test { useJUnitPlatform() } kotlin { jvmToolchain(17) } // modulo/build.gradle.kts plugins { id(\u0026#34;kotlin-library-conventions\u0026#34;) // aplica toda a configuracao } dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0\u0026#34;) } Migração de Groovy para Kotlin DSL A migração pode ser feita arquivo por arquivo:\nRenomear settings.gradle para settings.gradle.kts e ajustar a sintaxe Migrar build.gradle do projeto raiz para build.gradle.kts Migrar cada modulo individualmente Principais mudancas na sintaxe:\n// Groovy -\u0026gt; Kotlin DSL // Aspas simples -\u0026gt; aspas duplas \u0026#39;texto\u0026#39; --\u0026gt; \u0026#34;texto\u0026#34; // Atribuicao sem = -\u0026gt; com = compileSdk 35 --\u0026gt; compileSdk = 35 // Strings sem parenteses -\u0026gt; com parenteses implementation \u0026#39;lib:1.0\u0026#39; --\u0026gt; implementation(\u0026#34;lib:1.0\u0026#34;) // Property access -\u0026gt; metodo set mainClass = \u0026#39;Main\u0026#39; --\u0026gt; mainClass.set(\u0026#34;Main\u0026#34;) // Boolean properties minifyEnabled true --\u0026gt; isMinifyEnabled = true Quando usar cada um Escolha Kotlin DSL quando: Você inicia um projeto novo A equipe trabalha com Kotlin e valoriza segurança de tipos O projeto e multi-modulo com configuração compartilhada Você quer autocompletar e navegação confiavel na IDE Você esta migrando gradualmente um projeto existente Mantenha Groovy DSL quando: O projeto legado funciona bem e não há tempo para migrar A equipe esta mais confortavel com Groovy Você usa plugins que tem documentação apenas em Groovy A performance do primeiro build e crítica no CI Veredito Em 2026, o Kotlin DSL e a escolha padrão e recomendada para projetos Gradle com Kotlin. O suporte superior da IDE, segurança de tipos e a tendencia do ecossistema (novos templates do Google e JetBrains usam Kotlin DSL) tornam a migacao inevitavel para a maioria dos projetos. O Groovy DSL permanece funcional e suportado, mas seu uso em novos projetos e cada vez mais raro. Se você esta comecando, va direto para Kotlin DSL. Se tem um projeto Groovy existente, planeje a migração gradual quando houver oportunidade.\n","permalink":"https://kotlin.dev.br/comparacoes/gradle-kotlin-vs-groovy/","summary":"\u003ch2 id=\"gradle-kotlin-dsl-vs-groovy-dsl-configuração-de-build-em-2026\"\u003eGradle Kotlin DSL vs Groovy DSL: configuração de build em 2026\u003c/h2\u003e\n\u003cp\u003eO Gradle suporta dois DSLs para configuração de build: Groovy (histórico, arquivos \u003ccode\u003e.gradle\u003c/code\u003e) e Kotlin (moderno, arquivos \u003ccode\u003e.gradle.kts\u003c/code\u003e). Em 2026, o Kotlin DSL é a escolha padrão para novos projetos, mas muitos projetos legados ainda usam Groovy. Este artigo compara as duas opções em detalhes práticos.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracteristica\u003c/th\u003e\n          \u003cth\u003eKotlin DSL (.gradle.kts)\u003c/th\u003e\n          \u003cth\u003eGroovy DSL (.gradle)\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eExtensao\u003c/td\u003e\n          \u003ctd\u003e.gradle.kts\u003c/td\u003e\n          \u003ctd\u003e.gradle\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTipagem\u003c/td\u003e\n          \u003ctd\u003eEstática\u003c/td\u003e\n          \u003ctd\u003eDinamica\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAutocompletar IDE\u003c/td\u003e\n          \u003ctd\u003eCompleto\u003c/td\u003e\n          \u003ctd\u003eLimitado\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eNavegação ao código fonte\u003c/td\u003e\n          \u003ctd\u003eSim\u003c/td\u003e\n          \u003ctd\u003eParcial\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDocumentação inline\u003c/td\u003e\n          \u003ctd\u003eSim (KDoc)\u003c/td\u003e\n          \u003ctd\u003eLimitada\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eRefatoração\u003c/td\u003e\n          \u003ctd\u003eSuportada\u003c/td\u003e\n          \u003ctd\u003eLimitada\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePerformance de compilação\u003c/td\u003e\n          \u003ctd\u003eMais lenta (primeiro build)\u003c/td\u003e\n          \u003ctd\u003eMais rápida\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCache de scripts\u003c/td\u003e\n          \u003ctd\u003eEficiente (apos primeiro build)\u003c/td\u003e\n          \u003ctd\u003eEficiente\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePadrao novos projetos\u003c/td\u003e\n          \u003ctd\u003eSim (desde Gradle 8+)\u003c/td\u003e\n          \u003ctd\u003eLegado\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"sintaxe-comparada\"\u003eSintaxe comparada\u003c/h2\u003e\n\u003ch3 id=\"configuração-básica-do-projeto\"\u003eConfiguração básica do projeto\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eKotlin DSL:\u003c/strong\u003e\u003c/p\u003e","title":"Gradle Kotlin DSL vs Groovy DSL: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Design patterns são solucoes recorrentes para problemas comuns no desenvolvimento de software. Kotlin traz recursos da linguagem que tornam muitos desses padrões mais concisos e expressivos do que em Java. Neste artigo, vamos implementar os padrões mais importantes usando recursos idiomáticos de Kotlin.\nSingleton Em Java, implementar Singleton exige cuidado com threads e lazy initialization. Em Kotlin, a palavra-chave object resolve tudo em uma linha:\nobject BancoDeDados { private val conexoes = mutableListOf\u0026lt;String\u0026gt;() fun conectar(url: String) { conexoes.add(url) println(\u0026#34;Conectado a $url. Total: ${conexoes.size}\u0026#34;) } fun desconectarTodas() { conexoes.clear() println(\u0026#34;Todas as conexoes encerradas\u0026#34;) } } fun main() { BancoDeDados.conectar(\u0026#34;jdbc:postgresql://localhost/app\u0026#34;) BancoDeDados.conectar(\u0026#34;jdbc:postgresql://localhost/cache\u0026#34;) BancoDeDados.desconectarTodas() } O compilador Kotlin garante que a instancia e criada de forma thread-safe e lazy. Nao e necessário double-checked locking nem enum tricks.\nFactory Method O Factory Method encapsula a criação de objetos, permitindo que subclasses decidam qual tipo instanciar. Em Kotlin, companion objects com funções factory são a abordagem idiomatica:\nsealed class Notificacao { abstract fun enviar(destinatario: String, mensagem: String) class EmailNotificacao(private val servidorSmtp: String) : Notificacao() { override fun enviar(destinatario: String, mensagem: String) { println(\u0026#34;Email para $destinatario via $servidorSmtp: $mensagem\u0026#34;) } } class SmsNotificacao(private val provedor: String) : Notificacao() { override fun enviar(destinatario: String, mensagem: String) { println(\u0026#34;SMS para $destinatario via $provedor: $mensagem\u0026#34;) } } class PushNotificacao(private val plataforma: String) : Notificacao() { override fun enviar(destinatario: String, mensagem: String) { println(\u0026#34;Push para $destinatario na $plataforma: $mensagem\u0026#34;) } } companion object { fun criar(tipo: String): Notificacao = when (tipo) { \u0026#34;email\u0026#34; -\u0026gt; EmailNotificacao(\u0026#34;smtp.empresa.com\u0026#34;) \u0026#34;sms\u0026#34; -\u0026gt; SmsNotificacao(\u0026#34;twilio\u0026#34;) \u0026#34;push\u0026#34; -\u0026gt; PushNotificacao(\u0026#34;firebase\u0026#34;) else -\u0026gt; throw IllegalArgumentException(\u0026#34;Tipo desconhecido: $tipo\u0026#34;) } } } fun main() { val notificacao = Notificacao.criar(\u0026#34;email\u0026#34;) notificacao.enviar(\u0026#34;ana@email.com\u0026#34;, \u0026#34;Bem-vinda ao sistema\u0026#34;) val sms = Notificacao.criar(\u0026#34;sms\u0026#34;) sms.enviar(\u0026#34;+5511999887766\u0026#34;, \u0026#34;Seu codigo: 1234\u0026#34;) } A combinacao de sealed class com companion object factory cria um padrão robusto onde o compilador garante que todos os tipos são tratados em expressoes when.\nBuilder O pattern Builder simplifica a criação de objetos com muitos parametros. Em Kotlin, parametros nomeados e valores padrão frequentemente eliminam a necessidade de um Builder explicito:\n// Abordagem idiomatica: parametros nomeados com valores padrao data class ServidorConfig( val host: String = \u0026#34;localhost\u0026#34;, val porta: Int = 8080, val maxConexoes: Int = 100, val timeout: Long = 30_000, val ssl: Boolean = false, val logLevel: String = \u0026#34;INFO\u0026#34; ) fun main() { val config = ServidorConfig( host = \u0026#34;api.empresa.com\u0026#34;, porta = 443, ssl = true, logLevel = \u0026#34;DEBUG\u0026#34; ) println(config) } Quando a construcao envolve lógica mais complexa, um DSL Builder e mais apropriado:\nclass QueryBuilder { private var tabela: String = \u0026#34;\u0026#34; private val colunas = mutableListOf\u0026lt;String\u0026gt;() private val condicoes = mutableListOf\u0026lt;String\u0026gt;() private var ordenacao: String? = null private var limite: Int? = null fun de(tabela: String) = apply { this.tabela = tabela } fun colunas(vararg cols: String) = apply { colunas.addAll(cols) } fun onde(condicao: String) = apply { condicoes.add(condicao) } fun ordenarPor(coluna: String) = apply { ordenacao = coluna } fun limitar(n: Int) = apply { limite = n } fun build(): String { require(tabela.isNotBlank()) { \u0026#34;Tabela e obrigatoria\u0026#34; } val cols = if (colunas.isEmpty()) \u0026#34;*\u0026#34; else colunas.joinToString(\u0026#34;, \u0026#34;) val sql = StringBuilder(\u0026#34;SELECT $cols FROM $tabela\u0026#34;) if (condicoes.isNotEmpty()) { sql.append(\u0026#34; WHERE ${condicoes.joinToString(\u0026#34; AND \u0026#34;)}\u0026#34;) } ordenacao?.let { sql.append(\u0026#34; ORDER BY $it\u0026#34;) } limite?.let { sql.append(\u0026#34; LIMIT $it\u0026#34;) } return sql.toString() } } fun query(bloco: QueryBuilder.() -\u0026gt; Unit): String { return QueryBuilder().apply(bloco).build() } fun main() { val sql = query { de(\u0026#34;usuarios\u0026#34;) colunas(\u0026#34;nome\u0026#34;, \u0026#34;email\u0026#34;, \u0026#34;idade\u0026#34;) onde(\u0026#34;idade \u0026gt; 18\u0026#34;) onde(\u0026#34;ativo = true\u0026#34;) ordenarPor(\u0026#34;nome\u0026#34;) limitar(50) } println(sql) // SELECT nome, email, idade FROM usuarios WHERE idade \u0026gt; 18 AND ativo = true ORDER BY nome LIMIT 50 } Observer O pattern Observer define uma dependência um-para-muitos entre objetos. Em Kotlin, StateFlow e SharedFlow do kotlinx.coroutines são a implementação moderna desse padrão:\nimport kotlinx.coroutines.* import kotlinx.coroutines.flow.* class LojaDeEstado\u0026lt;T\u0026gt;(valorInicial: T) { private val _estado = MutableStateFlow(valorInicial) val estado: StateFlow\u0026lt;T\u0026gt; = _estado.asStateFlow() fun atualizar(transformacao: (T) -\u0026gt; T) { _estado.value = transformacao(_estado.value) } } data class AppState( val usuario: String = \u0026#34;\u0026#34;, val logado: Boolean = false, val itensCarrinho: Int = 0 ) fun main() = runBlocking { val loja = LojaDeEstado(AppState()) // Observador 1: UI val jobUI = launch { loja.estado.collect { estado -\u0026gt; println(\u0026#34;[UI] Usuario: ${estado.usuario}, Carrinho: ${estado.itensCarrinho}\u0026#34;) } } // Observador 2: Analytics val jobAnalytics = launch { loja.estado .filter { it.logado } .collect { estado -\u0026gt; println(\u0026#34;[Analytics] Evento: usuario ${estado.usuario} ativo\u0026#34;) } } delay(100) loja.atualizar { it.copy(usuario = \u0026#34;Ana\u0026#34;, logado = true) } delay(100) loja.atualizar { it.copy(itensCarrinho = 3) } delay(100) jobUI.cancel() jobAnalytics.cancel() } Para uma implementação clássica sem coroutines:\ninterface Observador\u0026lt;T\u0026gt; { fun atualizar(valor: T) } class EventBus\u0026lt;T\u0026gt; { private val observadores = mutableListOf\u0026lt;Observador\u0026lt;T\u0026gt;\u0026gt;() fun inscrever(observador: Observador\u0026lt;T\u0026gt;) { observadores.add(observador) } fun cancelar(observador: Observador\u0026lt;T\u0026gt;) { observadores.remove(observador) } fun notificar(valor: T) { observadores.forEach { it.atualizar(valor) } } } Strategy O pattern Strategy permite trocar algoritmos em tempo de execução. Em Kotlin, funções de ordem superior tornam esse padrão extremamente conciso:\ndata class Produto(val nome: String, val preco: Double, val quantidade: Int) // Estrategias como funcoes de primeira classe typealias EstrategiaDesconto = (Double) -\u0026gt; Double val semDesconto: EstrategiaDesconto = { total -\u0026gt; total } val desconto10Porcento: EstrategiaDesconto = { total -\u0026gt; total * 0.90 } val desconto20Porcento: EstrategiaDesconto = { total -\u0026gt; total * 0.80 } val descontoProgressivo: EstrategiaDesconto = { total -\u0026gt; when { total \u0026gt; 1000 -\u0026gt; total * 0.85 total \u0026gt; 500 -\u0026gt; total * 0.90 total \u0026gt; 200 -\u0026gt; total * 0.95 else -\u0026gt; total } } class Carrinho { private val itens = mutableListOf\u0026lt;Produto\u0026gt;() fun adicionar(produto: Produto) { itens.add(produto) } fun calcularTotal(estrategia: EstrategiaDesconto): Double { val subtotal = itens.sumOf { it.preco * it.quantidade } return estrategia(subtotal) } } fun main() { val carrinho = Carrinho() carrinho.adicionar(Produto(\u0026#34;Notebook\u0026#34;, 3500.0, 1)) carrinho.adicionar(Produto(\u0026#34;Mouse\u0026#34;, 150.0, 2)) println(\u0026#34;Sem desconto: R$ ${\u0026#34;%.2f\u0026#34;.format(carrinho.calcularTotal(semDesconto))}\u0026#34;) println(\u0026#34;10% off: R$ ${\u0026#34;%.2f\u0026#34;.format(carrinho.calcularTotal(desconto10Porcento))}\u0026#34;) println(\u0026#34;Progressivo: R$ ${\u0026#34;%.2f\u0026#34;.format(carrinho.calcularTotal(descontoProgressivo))}\u0026#34;) } Decorator O pattern Decorator adiciona comportamento a objetos sem alterar sua classe. Em Kotlin, extension functions e delegação com by tornam isso elegante:\ninterface Logger { fun log(mensagem: String) } class ConsoleLogger : Logger { override fun log(mensagem: String) { println(mensagem) } } class TimestampLogger(private val inner: Logger) : Logger by inner { override fun log(mensagem: String) { val agora = java.time.LocalDateTime.now() inner.log(\u0026#34;[$agora] $mensagem\u0026#34;) } } class PrefixLogger(private val inner: Logger, private val prefixo: String) : Logger by inner { override fun log(mensagem: String) { inner.log(\u0026#34;[$prefixo] $mensagem\u0026#34;) } } fun main() { val logger = PrefixLogger( TimestampLogger(ConsoleLogger()), \u0026#34;APP\u0026#34; ) logger.log(\u0026#34;Aplicação iniciada\u0026#34;) logger.log(\u0026#34;Processando requisicao\u0026#34;) // [APP] [2026-03-17T10:30:00] Aplicação iniciada } Adapter O Adapter converte a interface de uma classe para outra esperada pelo cliente. A delegação de Kotlin com by simplifica:\n// Sistema legado class SistemaLegado { fun buscarDadosXml(): String { return \u0026#34;\u0026lt;usuario\u0026gt;\u0026lt;nome\u0026gt;Ana\u0026lt;/nome\u0026gt;\u0026lt;idade\u0026gt;28\u0026lt;/idade\u0026gt;\u0026lt;/usuario\u0026gt;\u0026#34; } } // Interface moderna esperada interface FonteDeDados { fun buscarUsuario(): Map\u0026lt;String, String\u0026gt; } // Adapter class SistemaLegadoAdapter(private val legado: SistemaLegado) : FonteDeDados { override fun buscarUsuario(): Map\u0026lt;String, String\u0026gt; { val xml = legado.buscarDadosXml() // Parsing simplificado para exemplo val nome = Regex(\u0026#34;\u0026lt;nome\u0026gt;(.*?)\u0026lt;/nome\u0026gt;\u0026#34;).find(xml)?.groupValues?.get(1) ?: \u0026#34;\u0026#34; val idade = Regex(\u0026#34;\u0026lt;idade\u0026gt;(.*?)\u0026lt;/idade\u0026gt;\u0026#34;).find(xml)?.groupValues?.get(1) ?: \u0026#34;\u0026#34; return mapOf(\u0026#34;nome\u0026#34; to nome, \u0026#34;idade\u0026#34; to idade) } } fun exibirDados(fonte: FonteDeDados) { val dados = fonte.buscarUsuario() println(\u0026#34;Nome: ${dados[\u0026#34;nome\u0026#34;]}, Idade: ${dados[\u0026#34;idade\u0026#34;]}\u0026#34;) } fun main() { val legado = SistemaLegado() val adapter = SistemaLegadoAdapter(legado) exibirDados(adapter) // Nome: Ana, Idade: 28 } State O pattern State permite que um objeto altere seu comportamento quando seu estado interno muda. Sealed classes em Kotlin são perfeitas para isso:\nsealed class EstadoPedido { abstract fun proximo(): EstadoPedido abstract fun descricao(): String data object Criado : EstadoPedido() { override fun proximo() = Pago override fun descricao() = \u0026#34;Pedido criado, aguardando pagamento\u0026#34; } data object Pago : EstadoPedido() { override fun proximo() = Enviado override fun descricao() = \u0026#34;Pagamento confirmado, preparando envio\u0026#34; } data object Enviado : EstadoPedido() { override fun proximo() = Entregue override fun descricao() = \u0026#34;Pedido enviado, em transito\u0026#34; } data object Entregue : EstadoPedido() { override fun proximo() = this override fun descricao() = \u0026#34;Pedido entregue ao destinatario\u0026#34; } } class Pedido(val id: String) { var estado: EstadoPedido = EstadoPedido.Criado private set fun avancar() { estado = estado.proximo() println(\u0026#34;Pedido $id: ${estado.descricao()}\u0026#34;) } } fun main() { val pedido = Pedido(\u0026#34;PED-001\u0026#34;) pedido.avancar() // Pagamento confirmado pedido.avancar() // Pedido enviado pedido.avancar() // Pedido entregue pedido.avancar() // Continua entregue } Conclusão Kotlin transforma a implementação de design patterns. Recursos como object declarations, sealed classes, extension functions, funções de ordem superior e delegação com by eliminam o boilerplate que torna esses padrões verbosos em Java. O resultado e um código mais expressivo é fácil de manter. Cada linguagem moderna tem sua abordagem para esses padrões — Go prefere composição sobre herança com interfaces implícitas, e Rust usa traits e enums para padrões idiomáticos. A chave e conhecer os recursos da linguagem e aplica-los onde cada padrão se encaixa naturalmente. Nao force um padrão quando a linguagem já oferece uma solução idiomatica mais simples.\n","permalink":"https://kotlin.dev.br/blog/kotlin-design-patterns/","summary":"\u003cp\u003eDesign patterns são solucoes recorrentes para problemas comuns no desenvolvimento de software. Kotlin traz recursos da linguagem que tornam muitos desses padrões mais concisos e expressivos do que em Java. Neste artigo, vamos implementar os padrões mais importantes usando recursos idiomáticos de Kotlin.\u003c/p\u003e\n\u003ch2 id=\"singleton\"\u003eSingleton\u003c/h2\u003e\n\u003cp\u003eEm Java, implementar Singleton exige cuidado com threads e lazy initialization. Em Kotlin, a palavra-chave \u003ccode\u003eobject\u003c/code\u003e resolve tudo em uma linha:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eobject\u003c/span\u003e \u003cspan class=\"nc\"\u003eBancoDeDados\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eprivate\u003c/span\u003e \u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003econexoes\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emutableListOf\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003econectar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003econexoes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Conectado a \u003c/span\u003e\u003cspan class=\"si\"\u003e$url\u003c/span\u003e\u003cspan class=\"s2\"\u003e. Total: \u003c/span\u003e\u003cspan class=\"si\"\u003e${conexoes.size}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003edesconectarTodas\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003econexoes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclear\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eprintln\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Todas as conexoes encerradas\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efun\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nc\"\u003eBancoDeDados\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econectar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;jdbc:postgresql://localhost/app\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nc\"\u003eBancoDeDados\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econectar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;jdbc:postgresql://localhost/cache\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nc\"\u003eBancoDeDados\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edesconectarTodas\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eO compilador Kotlin garante que a instancia e criada de forma thread-safe e lazy. Nao e necessário double-checked locking nem enum tricks.\u003c/p\u003e","title":"Design Patterns em Kotlin: Guia Prático com Exemplos | Kotlin Brasil"},{"content":"Empresas que usam Kotlin no Brasil: mapa completo em 2026 Conhecer as empresas que utilizam Kotlin no Brasil e fundamental para quem busca oportunidades na area. Saber onde a tecnologia e adotada ajuda a direcionar candidaturas, entender o mercado e planejar sua carreira. Este artigo apresenta um mapeamento abrangente das empresas brasileiras que utilizam Kotlin em producao, organizadas por setor e com informações sobre como cada uma aplica a linguagem.\nFintechs e bancos digitais O setor financeiro é o maior empregador de desenvolvedores Kotlin no Brasil. A combinacao de aplicativos mobile de alta performance com backends robustos e escalaveis faz de Kotlin a escolha natural para esse segmento.\nNubank O Nubank é um dos maiores casos de sucesso de Kotlin no Brasil e no mundo. A empresa utiliza Kotlin extensivamente em seu aplicativo Android e também no backend com microsservicos. Com milhares de engenheiros, o Nubank é um dos maiores empregadores de desenvolvedores Kotlin no pais. A empresa e conhecida por sua cultura de engenharia forte e processos seletivos rigorosos.\nPicPay O PicPay adotou Kotlin tanto no Android quanto no backend. A plataforma de pagamentos processa milhoes de transacoes e depende de equipes de desenvolvimento Kotlin para manter e evoluir seus sistemas. A empresa oferece oportunidades em diferentes niveis de experiência.\nC6 Bank O C6 Bank utiliza Kotlin em seu aplicativo Android e em parte do backend. Como banco digital em crescimento, a empresa contrata regularmente desenvolvedores Kotlin para expandir suas funcionalidades.\nInter O banco Inter adotou Kotlin para seu super app, que combina serviços bancarios, marketplace e investimentos. A complexidade do aplicativo exige profissionais com conhecimento avançado em Kotlin e arquitetura de aplicações.\nItau O maior banco privado do Brasil utiliza Kotlin em seus aplicativos mobile e esta em processo de modernizacao de seus sistemas legados. O Itau oferece oportunidades em um ambiente de grande escala com impacto direto em milhoes de usuários.\nE-commerce e marketplaces Mercado Livre O Mercado Livre é uma das maiores empresas de tecnologia da America Latina e utiliza Kotlin extensivamente em seu aplicativo Android e em serviços backend. A empresa investe em tecnologia de ponta e oferece salários competitivos para desenvolvedores Kotlin.\nMagazine Luiza A transformacao digital da Magalu incluiu a adoção de Kotlin em seu aplicativo e em parte da infraestrutura de backend. O Luizalabs, braco de tecnologia da empresa, contrata profissionais Kotlin regularmente.\nAmericanas O grupo Americanas utiliza Kotlin em suas plataformas de e-commerce mobile. A empresa oferece oportunidades tanto no Rio de Janeiro quanto em São Paulo.\nAmazon Brasil A operação brasileira da Amazon emprega desenvolvedores Kotlin para o aplicativo de compras e serviços relacionados. A empresa segue os padrões de engenharia da Amazon global.\nDelivery e mobilidade iFood O iFood é uma das empresas que mais contrata desenvolvedores Kotlin no Brasil. O aplicativo principal e os serviços de backend processam milhoes de pedidos e dependem de equipes grandes e especializadas. A empresa oferece um ambiente de engenharia maduro com desafios tecnicos significativos.\nRappi A Rappi utiliza Kotlin em seu aplicativo Android e contrata regularmente no Brasil. A empresa oferece um ambiente dinamico de startup com operação em vários paises da America Latina.\n99 A plataforma de mobilidade utiliza Kotlin em seu aplicativo Android e em serviços backend. A empresa, que faz parte do grupo DiDi, oferece oportunidades com exposicao a desafios de engenharia de grande escala.\nSaude digital Dr. Consulta A plataforma de saude utiliza Kotlin em suas aplicações mobile e backend. A empresa busca profissionais que queiram combinar tecnologia com impacto social.\nAlice A operadora de saude digital utiliza Kotlin em sua plataforma, oferecendo oportunidades em um segmento em rápido crescimento.\nConexa Saude Plataforma de telemedicina que adotou Kotlin para seu aplicativo e serviços. O crescimento da telemedicina no Brasil gera demanda constante por profissionais.\nTecnologia e SaaS RD Station A empresa catarinense de marketing digital utiliza Kotlin em alguns de seus serviços. Com sede em Florianopolis, oferece qualidade de vida e salários competitivos.\nHotmart A plataforma de produtos digitais de Belo Horizonte utiliza Kotlin em parte de sua stack. A empresa e conhecida por sua cultura de inovacao e ambiente de trabalho diferenciado.\nVTEX A plataforma de e-commerce enterprise utiliza Kotlin em alguns de seus serviços. A VTEX oferece oportunidades de trabalho com clientes globais.\nCI\u0026amp;T A consultoria de tecnologia brasileira utiliza Kotlin em projetos para clientes de grande porte em diversos setores. E uma boa opção para profissionais que gostam de variedade de projetos.\nTake Blip A empresa de chatbots de Belo Horizonte utiliza Kotlin em parte de sua plataforma. Oferece oportunidades em um nicho específico e em crescimento.\nStartups em estagio inicial Alem das empresas estabelecidas, centenas de startups brasileiras em estagio inicial escolhem Kotlin para seus primeiros produtos. Aceleradoras como Endeavor, ACE e Y Combinator Brasil abrigam startups que frequentemente buscam desenvolvedores Kotlin para construir seus MVPs e produtos iniciais.\nTrabalhar em startups oferece a oportunidade de maior responsabilidade, aprendizado acelerado e potencial de ganhos com equity, embora com menor estabilidade em comparação com empresas estabelecidas.\nComo se candidatar Para se candidatar a vagas nessas empresas, mantenha seu perfil no LinkedIn atualizado e siga as paginas de carreira das empresas de seu interesse. A maioria possui programas de indicacao que oferecem bonus para funcionarios que indicam candidatos contratados, entao construir uma rede de contatos nessas empresas é uma estrategia eficaz.\nParticipe de eventos e meetups patrocinados por essas empresas. Muitas realizam tech talks abertas, hackathons e programas de mentoria que servem como porta de entrada para oportunidades.\nConclusão O ecossistema de empresas que utilizam Kotlin no Brasil em 2026 e amplo e diversificado, cobrindo setores como financas, e-commerce, delivery, saude, educacao e tecnologia. Desde gigantes como Nubank e Mercado Livre até startups em estagio inicial, as oportunidades são abundantes para profissionais que dominam a linguagem. Conhecer esse mapa de empresas permite direcionar sua carreira de forma estrategica, focando nos setores e empresas que mais se alinham com seus objetivos profissionais.\n","permalink":"https://kotlin.dev.br/carreira/kotlin-empresas-brasil/","summary":"\u003ch2 id=\"empresas-que-usam-kotlin-no-brasil-mapa-completo-em-2026\"\u003eEmpresas que usam Kotlin no Brasil: mapa completo em 2026\u003c/h2\u003e\n\u003cp\u003eConhecer as empresas que utilizam Kotlin no Brasil e fundamental para quem busca oportunidades na area. Saber onde a tecnologia e adotada ajuda a direcionar candidaturas, entender o mercado e planejar sua carreira. Este artigo apresenta um mapeamento abrangente das empresas brasileiras que utilizam Kotlin em producao, organizadas por setor e com informações sobre como cada uma aplica a linguagem.\u003c/p\u003e","title":"Empresas que Usam Kotlin no Brasil em 2026 | Kotlin Brasil"},{"content":"Desenvolvedor Kotlin freelancer: guia completo para 2026 O trabalho freelance como desenvolvedor Kotlin oferece liberdade, flexibilidade e potencial de remuneracao superior ao emprego tradicional. No entanto, a carreira autonoma também traz desafios unicos que exigem preparacao e planejamento. Este guia aborda todos os aspectos de trabalhar como freelancer Kotlin em 2026, desde encontrar clientes até gerenciar aspectos legais e financeiros.\nO mercado freelance para Kotlin O mercado de freelance para desenvolvedores Kotlin esta em expansao. Empresas de todos os portes buscam profissionais autonomos para projetos de desenvolvimento Android, backend e multiplataforma. Startups sem equipe interna de desenvolvimento, empresas em fase de mvp, organizacoes que precisam de reforco temporario e empresas internacionais que contratam desenvolvedores brasileiros formam a base de clientes para freelancers Kotlin.\nA demanda e particularmente forte em desenvolvimento de aplicativos Android, criação de APIs e microsservicos backend, migração de projetos Java para Kotlin, desenvolvimento de MVPs para startups e consultoria técnica para empresas em transicao.\nFaixas de remuneracao Freelancers Kotlin no Brasil podem cobrar valores significativamente superiores ao equivalente CLT, refletindo a ausência de beneficios é a natureza temporaria dos projetos:\nNível Hora (Brasil) Hora (Internacional) Projeto mensal estimado Junior R$ 50 - R$ 100 USD 20 - USD 40 R$ 6.000 - R$ 12.000 Pleno R$ 100 - R$ 200 USD 40 - USD 80 R$ 12.000 - R$ 24.000 Senior R$ 200 - R$ 400 USD 80 - USD 150 R$ 24.000 - R$ 50.000 Esses valores consideram um volume de trabalho de 120 a 160 horas mensais. Profissionais que atuam no mercado internacional com clientes americanos e europeus frequentemente atingem as faixas superiores.\nOnde encontrar clientes e projetos Plataformas internacionais Toptal é a plataforma mais prestigiada para freelancers de elite. O processo seletivo e rigoroso, mas os projetos oferecem remuneracao premium e clientes de alto nível. Upwork é a maior plataforma de freelance do mundo, com volume consistente de projetos Kotlin. Freelancer.com também possui projetos de desenvolvimento mobile e backend. E o Fiverr, embora mais voltado para projetos menores, pode ser um ponto de entrada.\nPlataformas brasileiras Workana é a maior plataforma de freelance na America Latina. 99Freelas possui projetos de desenvolvimento em português. E GetNinjas oferece oportunidades para projetos de menor escala.\nNetworking e indicacoes A forma mais eficaz de conseguir projetos de alto valor e por meio de indicacoes. Construa relacionamentos com outros desenvolvedores, designers, gerentes de produto e empreendedores. Participe de meetups, conferencias e comunidades online. Muitos freelancers bem-sucedidos conseguem a maioria de seus projetos por meio de sua rede de contatos.\nAbordagem direta Identifique empresas que poderiam se beneficiar de desenvolvimento Kotlin e entre em contato diretamente. Startups em estagio inicial, empresas com aplicativos Android desatualizados e organizacoes em processo de modernizacao tecnologica são alvos estrategicos.\nPrecificacao e negociacao Cobranca por hora versus por projeto A cobranca por hora oferece previsibilidade de receita e proteção contra mudancas de escopo. A cobranca por projeto pode ser mais lucrativa, mas exige experiência para estimar o esforco com precisao. Para iniciantes no freelance, a cobranca por hora e geralmente mais segura.\nComo definir seu valor hora Calcule seus custos fixos mensais incluindo aluguel, alimentacao, internet e saude. Adicione impostos e contribuicoes previdenciarias. Inclua uma margem para meses sem projeto. Divida pelo número de horas faturadas por mes. E adicione uma margem de lucro. Como referência, um freelancer Kotlin pleno que deseja uma renda liquida de R$ 12.000 precisa cobrar aproximadamente R$ 120 a R$ 150 por hora, considerando impostos e horas não faturadas.\nNegociacao com clientes Apresente seu valor com confianca baseada em resultados anteriores. Offereca opções com escopos diferentes para dar ao cliente flexibilidade. Defina claramente o que esta incluido é o que constitui trabalho adicional. E sempre formalize acordos por escrito antes de iniciar o trabalho.\nAspectos legais e tributarios Registro como PJ A maioria dos freelancers Kotlin opera como pessoa juridica, geralmente no regime do Simples Nacional com CNAE de desenvolvimento de software. O custo mensal com contador e impostos varia entre 6 e 15 por cento do faturamento, dependendo da faixa de receita.\nContratos Sempre trabalhe com contratos que definam escopo, prazos, forma de pagamento, propriedade intelectual e condições de cancelamento. Para clientes internacionais, utilize contratos em ingles e defina a jurisdicao aplicavel.\nRecebimento de pagamentos internacionais Para clientes estrangeiros, serviços como Wise, Payoneer e Husky oferecem transferencias internacionais com taxas competitivas. Mantenha documentação completa de todas as transacoes para fins fiscais.\nConstruindo uma carreira freelance sustentavel Especialize-se Freelancers especialistas cobram mais e atraem melhores projetos. Defina um nicho, seja desenvolvimento Android com Jetpack Compose, backend com Ktor, migração Java para Kotlin ou consultoria em Kotlin Multiplatform.\nConstrua um portfolio visivel Mantenha um site pessoal com seus projetos, depoimentos de clientes e areas de especialidade. Um perfil no GitHub com projetos ativos complementa sua presenca online.\nGerencie seu tempo e energia O desafio do freelance não e apenas técnico, mas também de gestao. Reserve tempo para buscar novos projetos, gerenciar aspectos administrativos e investir em aprendizado. Evite a armadilha de trabalhar ininterruptamente sem pausas.\nMantenha uma reserva financeira A irregularidade de receita é uma realidade do freelance. Mantenha uma reserva de pelo menos seis meses de despesas para navegar periodos entre projetos sem estresse financeiro.\nInvista em relacionamentos de longo prazo Clientes recorrentes são o alicerce de uma carreira freelance estavel. Entregue qualidade consistente, comunique-se de forma proativa e construa confianca para que clientes retornem com novos projetos.\nDesafios e como supera-los O isolamento pode ser combatido participando de coworkings e comunidades. A instabilidade de receita se resolve com planejamento financeiro e diversificacao de clientes. A falta de beneficios exige que você contrate plano de saude e contribua para previdencia de forma autonoma. E a dificuldade de desconectar do trabalho se resolve com limites claros de horario e espaco de trabalho.\nConclusão Trabalhar como desenvolvedor Kotlin freelancer em 2026 é uma carreira viável e potencialmente muito lucrativa. Com remuneracoes que podem superar significativamente o emprego tradicional é a liberdade de escolher projetos e horarios, o freelance atrai cada vez mais profissionais qualificados. O sucesso nessa modalidade depende da combinacao de excelencia técnica, habilidades de negócio e disciplina pessoal.\n","permalink":"https://kotlin.dev.br/carreira/dev-kotlin-freelancer/","summary":"\u003ch2 id=\"desenvolvedor-kotlin-freelancer-guia-completo-para-2026\"\u003eDesenvolvedor Kotlin freelancer: guia completo para 2026\u003c/h2\u003e\n\u003cp\u003eO trabalho freelance como desenvolvedor Kotlin oferece liberdade, flexibilidade e potencial de remuneracao superior ao emprego tradicional. No entanto, a carreira autonoma também traz desafios unicos que exigem preparacao e planejamento. Este guia aborda todos os aspectos de trabalhar como freelancer Kotlin em 2026, desde encontrar clientes até gerenciar aspectos legais e financeiros.\u003c/p\u003e\n\u003ch2 id=\"o-mercado-freelance-para-kotlin\"\u003eO mercado freelance para Kotlin\u003c/h2\u003e\n\u003cp\u003eO mercado de freelance para desenvolvedores Kotlin esta em expansao. Empresas de todos os portes buscam profissionais autonomos para projetos de desenvolvimento Android, backend e multiplataforma. Startups sem equipe interna de desenvolvimento, empresas em fase de mvp, organizacoes que precisam de reforco temporario e empresas internacionais que contratam desenvolvedores brasileiros formam a base de clientes para freelancers Kotlin.\u003c/p\u003e","title":"Desenvolvedor Kotlin Freelancer: Guia para Trabalhar por Conta Propria | Kotlin Brasil"},{"content":"Kotlin Multiplatform vs React Native: qual escolher em 2026? Kotlin Multiplatform (KMP) e React Native (RN) representam abordagens distintas para desenvolvimento cross-platform. Enquanto KMP compartilha lógica de negócio mantendo UI nativa, React Native renderiza componentes nativos a partir de JavaScript/TypeScript. Este artigo analisa ambas as opções em profundidade para orientar sua decisao técnica.\nVisao geral Caracteristica Kotlin Multiplatform React Native Empresa JetBrains Meta (Facebook) Linguagem Kotlin JavaScript/TypeScript Arquitetura Compilação nativa Bridge / New Architecture (JSI) Compartilhamento Logica de negócio Logica + UI Componentes UI Nativos (SwiftUI/Compose) Nativos via bridge Hot reload Limitado Fast Refresh Ecossistema web Separado Compartilha com React Tipagem Estática forte Dinamica (TS: estática) Arquitetura e funcionamento Kotlin Multiplatform KMP compila código Kotlin para cada plataforma alvo. No Android, gera bytecode JVM. No iOS, gera código nativo ARM via Kotlin/Native. Nao há runtime intermediário nem bridge de comunicação. O código compartilhado e executado com a mesma performance de código nativo porque ele e código nativo.\n// commonMain - compartilhado entre plataformas class ProdutoRepositorio( private val api: ProdutoApi, private val cache: ProdutoCache ) { suspend fun buscarProdutos(categoria: String): List\u0026lt;Produto\u0026gt; { val cacheados = cache.buscar(categoria) if (cacheados.isNotEmpty()) return cacheados val produtos = api.listarPorCategoria(categoria) cache.salvar(categoria, produtos) return produtos } suspend fun buscarDetalhes(id: Long): ProdutoDetalhes { return api.detalhes(id) } } // commonMain - ViewModel compartilhado class CatalogoViewModel( private val repositorio: ProdutoRepositorio ) : ViewModel() { private val _produtos = MutableStateFlow\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt;(emptyList()) val produtos: StateFlow\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt; = _produtos.asStateFlow() private val _carregando = MutableStateFlow(false) val carregando: StateFlow\u0026lt;Boolean\u0026gt; = _carregando.asStateFlow() fun carregar(categoria: String) { viewModelScope.launch { _carregando.value = true try { _produtos.value = repositorio.buscarProdutos(categoria) } finally { _carregando.value = false } } } } React Native React Native executa JavaScript em um motor JS (Hermes) e comunica com componentes nativos. A New Architecture (introduzida no RN 0.74+) usa JSI (JavaScript Interface) para comunicação sincrona com o lado nativo, eliminando a bridge assíncrona antiga:\n// React Native com TypeScript interface Produto { id: number; nome: string; preco: number; categoria: string; } const useProdutos = (categoria: string) =\u0026gt; { const [produtos, setProdutos] = useState\u0026lt;Produto[]\u0026gt;([]); const [carregando, setCarregando] = useState(false); const carregar = useCallback(async () =\u0026gt; { setCarregando(true); try { const resposta = await fetch(`https://api.exemplo.com/produtos?cat=${categoria}`); const dados: Produto[] = await resposta.json(); setProdutos(dados); } catch (erro) { console.error(\u0026#39;Erro ao carregar produtos:\u0026#39;, erro); } finally { setCarregando(false); } }, [categoria]); useEffect(() =\u0026gt; { carregar(); }, [carregar]); return { produtos, carregando, recarregar: carregar }; }; const TelaCatalogo: React.FC = () =\u0026gt; { const { produtos, carregando } = useProdutos(\u0026#39;eletronicos\u0026#39;); if (carregando) return \u0026lt;ActivityIndicator /\u0026gt;; return ( \u0026lt;FlatList data={produtos} keyExtractor={(item) =\u0026gt; item.id.toString()} renderItem={({ item }) =\u0026gt; ( \u0026lt;View style={styles.card}\u0026gt; \u0026lt;Text style={styles.nome}\u0026gt;{item.nome}\u0026lt;/Text\u0026gt; \u0026lt;Text style={styles.preco}\u0026gt;R$ {item.preco.toFixed(2)}\u0026lt;/Text\u0026gt; \u0026lt;/View\u0026gt; )} /\u0026gt; ); }; Performance A performance e uma das maiores diferenças entre as duas abordagens.\nMetrica KMP React Native Startup (cold) Nativo +200-500ms (JS engine) Logica de negócio Compilada nativa Interpretada (Hermes) Renderizacao UI Nativa direta Nativa via bridge/JSI Animacoes 60/120fps nativo Reanimated: 60/120fps Uso de memória Nativo +30-50MB (JS runtime) Operações CPU intensivas Nativo 2-10x mais lento Para operações de I/O (rede, banco de dados), a diferenca e minima porque ambos delegam para código nativo. Para operações CPU intensivas como criptografia, processamento de imagem ou calculos complexos, KMP tem vantagem significativa porque o código e compilado nativamente.\nReact Native com a New Architecture e Hermes melhorou consideravelmente, mas ainda carrega o overhead de um runtime JavaScript.\nCompartilhamento de código KMP: lógica compartilhada, UI nativa projeto-kmp/ shared/ commonMain/ --\u0026gt; Logica compartilhada (Kotlin) androidMain/ --\u0026gt; Implementacoes Android iosMain/ --\u0026gt; Implementacoes iOS androidApp/ --\u0026gt; UI Android (Compose) iosApp/ --\u0026gt; UI iOS (SwiftUI) O código compartilhado tipicamente inclui: modelos de dados, repositórios, view models, validacoes, lógica de negócio, networking e acesso a banco. A UI e 100% nativa.\nReact Native: quase tudo compartilhado projeto-rn/ src/ components/ --\u0026gt; Componentes UI (React Native) hooks/ --\u0026gt; Logica compartilhada services/ --\u0026gt; API e serviços screens/ --\u0026gt; Telas android/ --\u0026gt; Código nativo Android (minimo) ios/ --\u0026gt; Código nativo iOS (minimo) React Native compartilha entre 85-95% do código, incluindo UI. Código nativo específico e necessário apenas para funcionalidades de plataforma sem modulo RN disponivel.\nSegurança de tipos Kotlin oferece tipagem estática forte nativa. TypeScript adiciona tipos a JavaScript, mas a verificação e em tempo de compilação apenas e pode ser burlada:\n// Kotlin: segurança de tipos garantida pelo compilador data class Pedido( val id: Long, val valor: Double, val itens: List\u0026lt;ItemPedido\u0026gt; ) fun calcularTotal(pedido: Pedido): Double { return pedido.itens.sumOf { it.preco * it.quantidade } } // Impossivel chamar com tipos errados // TypeScript: tipos podem ser contornados interface Pedido { id: number; valor: number; itens: ItemPedido[]; } function calcularTotal(pedido: Pedido): number { return pedido.itens.reduce((acc, item) =\u0026gt; acc + item.preco * item.quantidade, 0); } // \u0026#39;any\u0026#39; pode contornar a tipagem const resultado = calcularTotal({} as any); // compila mas falha em runtime Ecossistema e comunidade React Native React Native tem uma comunidade enorme e anos de maturidade. O ecossistema npm oferece bibliotecas para quase tudo, e desenvolvedores web com React podem transicionar rapidamente. Empresas como Meta, Microsoft, Shopify e Discord usam React Native em producao.\nKotlin Multiplatform KMP tem uma comunidade menor mas em crescimento acelerado. Empresas como Netflix, McDonald\u0026rsquo;s, VMware e Philips adotaram KMP. O ecossistema de bibliotecas KMP e menor que o de RN, mas cobre as necessidades principais e permite acesso a qualquer biblioteca nativa de cada plataforma.\nIntegração com equipes existentes Equipe Android + iOS Se você tem desenvolvedores Android (Kotlin) e iOS (Swift) separados, KMP permite que a equipe Android escreva o código compartilhado e a equipe iOS continue usando Swift para a UI. A transicao e gradual e não requer que ninguem aprenda uma nova linguagem para sua plataforma.\nEquipe web (React) Se você tem desenvolvedores React web, React Native e a escolha natural. Eles já conhecem React, JSX, hooks e o ecossistema npm. A transicao para mobile e suave, e muitos conceitos são transferiveis.\nQuando usar cada um Escolha Kotlin Multiplatform quando: Performance nativa e requisito crítico A equipe já tem desenvolvedores Android com Kotlin Você quer UI que siga perfeitamente as guidelines de cada plataforma O app precisa de operações CPU intensivas Segurança de tipos forte e prioridade Você quer adotar compartilhamento incrementalmente Escolha React Native quando: A equipe vem do ecossistema web/React Velocidade de desenvolvimento e prioridade sobre performance pura O app e predominantemente baseado em telas de formularios e listagens Você quer maximizar o compartilhamento de código (incluindo UI) Fast Refresh para iteracao rápida e importante Você também precisa de uma versão web (React Native Web) Veredito Em 2026, ambas as tecnologias são opções solidas para desenvolvimento cross-platform. KMP e superior quando performance nativa, segurança de tipos e experiência de plataforma são prioridades. React Native e superior quando velocidade de desenvolvimento, maximizacao de compartilhamento de código e aproveitamento de conhecimento web são mais importantes.\nA escolha ideal depende da composição da sua equipe e das prioridades do projeto. Se sua equipe e forte em Kotlin/Swift e você quer a melhor experiência nativa possível, KMP e o caminho. Se sua equipe e forte em JavaScript/TypeScript e você quer entregar rápido com maximo compartilhamento, React Native e a resposta. Nenhuma escolha e errada \u0026ndash; ambas resolvem o problema de cross-platform de formas diferentes e complementares. Para backend compartilhado entre plataformas, considere também Go para APIs de alta performance e Python para prototipagem rápida de serviços.\n","permalink":"https://kotlin.dev.br/comparacoes/kotlin-multiplatform-vs-react-native/","summary":"\u003ch2 id=\"kotlin-multiplatform-vs-react-native-qual-escolher-em-2026\"\u003eKotlin Multiplatform vs React Native: qual escolher em 2026?\u003c/h2\u003e\n\u003cp\u003eKotlin Multiplatform (KMP) e React Native (RN) representam abordagens distintas para desenvolvimento cross-platform. Enquanto KMP compartilha lógica de negócio mantendo UI nativa, React Native renderiza componentes nativos a partir de JavaScript/TypeScript. Este artigo analisa ambas as opções em profundidade para orientar sua decisao técnica.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracteristica\u003c/th\u003e\n          \u003cth\u003eKotlin Multiplatform\u003c/th\u003e\n          \u003cth\u003eReact Native\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eEmpresa\u003c/td\u003e\n          \u003ctd\u003eJetBrains\u003c/td\u003e\n          \u003ctd\u003eMeta (Facebook)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eLinguagem\u003c/td\u003e\n          \u003ctd\u003eKotlin\u003c/td\u003e\n          \u003ctd\u003eJavaScript/TypeScript\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eArquitetura\u003c/td\u003e\n          \u003ctd\u003eCompilação nativa\u003c/td\u003e\n          \u003ctd\u003eBridge / New Architecture (JSI)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCompartilhamento\u003c/td\u003e\n          \u003ctd\u003eLogica de negócio\u003c/td\u003e\n          \u003ctd\u003eLogica + UI\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eComponentes UI\u003c/td\u003e\n          \u003ctd\u003eNativos (SwiftUI/Compose)\u003c/td\u003e\n          \u003ctd\u003eNativos via bridge\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eHot reload\u003c/td\u003e\n          \u003ctd\u003eLimitado\u003c/td\u003e\n          \u003ctd\u003eFast Refresh\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eEcossistema web\u003c/td\u003e\n          \u003ctd\u003eSeparado\u003c/td\u003e\n          \u003ctd\u003eCompartilha com React\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTipagem\u003c/td\u003e\n          \u003ctd\u003eEstática forte\u003c/td\u003e\n          \u003ctd\u003eDinamica (TS: estática)\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"arquitetura-e-funcionamento\"\u003eArquitetura e funcionamento\u003c/h2\u003e\n\u003ch3 id=\"kotlin-multiplatform\"\u003eKotlin Multiplatform\u003c/h3\u003e\n\u003cp\u003eKMP compila código Kotlin para cada plataforma alvo. No Android, gera bytecode JVM. No iOS, gera código nativo ARM via Kotlin/Native. Nao há runtime intermediário nem bridge de comunicação. O código compartilhado e executado com a mesma performance de código nativo porque ele e código nativo.\u003c/p\u003e","title":"Kotlin Multiplatform vs React Native: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Transicao de Java para Kotlin: guia completo para sua carreira Se você é um desenvolvedor Java considerando a transicao para Kotlin, esta tomando uma decisao estrategica que pode impulsionar significativamente sua carreira. Kotlin foi projetado para ser uma evolução natural do Java, mantendo a interoperabilidade com a JVM enquanto oferece uma sintaxe mais moderna e produtiva. Este guia apresenta o caminho completo para fazer essa transicao de forma eficiente e estrategica.\nPor que migrar de Java para Kotlin? A transicao de Java para Kotlin não significa abandonar seus conhecimentos atuais, mas sim expandi-los. Existem razoes concretas que justificam essa mudanca.\nO mercado demanda Kotlin. No desenvolvimento Android, Kotlin é a linguagem preferida pelo Google desde 2019. No backend, a adoção de Kotlin com Spring Boot cresce ano a ano. E com Kotlin Multiplatform, novas oportunidades surgem que não existem no ecossistema Java puro.\nOs salários tendem a ser superiores. Profissionais que dominam Kotlin recebem em media 10 a 15 por cento a mais que desenvolvedores Java no mesmo nível, especialmente em posicoes Android e em empresas que valorizam tecnologias modernas.\nA produtividade aumenta. Kotlin elimina grande parte do boilerplate de Java, oferece null safety em nível de compilação e possui funcionalidades como data classes, extension functions e coroutines que tornam o desenvolvimento mais agil e menos propenso a erros.\nSuas habilidades Java que se transferem diretamente A boa noticia e que a maior parte do seu conhecimento Java se aplica diretamente em Kotlin. Você não esta comecando do zero.\nEcossistema JVM Todo o seu conhecimento sobre a JVM, incluindo garbage collection, classloading, memory model e performance tuning, se aplica integralmente em Kotlin. O bytecode gerado por Kotlin roda na mesma JVM que você já conhece.\nFrameworks e bibliotecas Spring Boot, Hibernate, Maven, Gradle e praticamente todas as bibliotecas Java funcionam perfeitamente com Kotlin. Você pode usar suas bibliotecas Java favoritas em projetos Kotlin sem nenhuma adaptacao.\nDesign patterns e arquitetura Os padrões de projeto e principios de arquitetura que você domina, como SOLID, Clean Architecture e DDD, são igualmente validos em Kotlin. Na verdade, muitos padrões ficam mais elegantes quando implementados em Kotlin.\nFerramentas e processos IntelliJ IDEA, que é a base do Android Studio, oferece suporte de primeira classe para Kotlin. Ferramentas de build como Gradle e Maven funcionam perfeitamente. E processos de CI/CD não requerem mudancas significativas.\nO que você precisa aprender Apesar da base transferivel, existem conceitos específicos de Kotlin que exigem estudo dedicado.\nNull safety O sistema de null safety de Kotlin e fundamentalmente diferente da abordagem do Java. Aprenda sobre tipos nulaveis com o sufixo interrogacao, operador safe call, operador Elvis, smart casts é a função let para operações seguras com nulaveis. Esse e provavelmente o conceito que mais muda a forma como você escreve código.\nData classes e sealed classes Data classes eliminam a necessidade de escrever equals, hashCode, toString e copy manualmente. Sealed classes são uma alternativa mais poderosa e segura ao padrão de enum com estado. Ambas são fundamentais no Kotlin idiomatico.\nExtension functions A capacidade de adicionar funções a classes existentes sem heranca é um dos recursos mais poderosos de Kotlin. Aprenda quando e como usar extension functions de forma eficaz.\nCoroutines Coroutines são a forma nativa de Kotlin para lidar com programação assíncrona. Se você esta acostumado com CompletableFuture ou RxJava em Java, coroutines representam uma abordagem mais intuitiva e menos propensa a erros. Estude suspend functions, scopes, dispatchers e flows.\nProgramação funcional Kotlin suporta programação funcional de forma mais natural que Java. Aprenda sobre lambdas, higher-order functions, funções inline, operadores de colecao e sequence para processamento lazy.\nKotlin idiomatico Existe uma diferenca significativa entre escrever Java em sintaxe Kotlin e escrever Kotlin idiomatico. Estude as convenções da linguagem, como o uso de when ao inves de cadeias de if-else, named arguments para clareza, funções de escopo como let, run, apply, also e with, é o padrão de builder com DSLs internas.\nTimeline de transicao recomendada Semana 1-2: Sintaxe básica Converta mentalmente sua base de Java para Kotlin. Pratique reescrevendo código Java simples em Kotlin. O Android Studio possui uma ferramenta de conversao automatica que pode ser usada como ponto de partida.\nSemana 3-4: Conceitos intermediarios Aprofunde-se em null safety, data classes, sealed classes e extension functions. Comece a escrever código Kotlin que não se parece com Java traduzido.\nMes 2: Coroutines e funcionalidades avançadas Estude coroutines em profundidade. Pratique com projetos que envolvem operações assíncronas, networking e acesso a banco de dados.\nMes 3: Especializacao Foque na sua area de atuacao. Se você trabalha com Android, mergulhe em Jetpack Compose. Se trabalha com backend, aprofunde-se em Ktor ou na configuração Kotlin-first do Spring Boot.\nMes 4-6: Consolidacao Construa projetos completos em Kotlin. Contribua para projetos open source. Atualize seu portfolio com projetos Kotlin.\nEstrategias de migração no trabalho Migração gradual Se você trabalha em um projeto Java existente, proponha a adoção gradual de Kotlin. Comece escrevendo testes em Kotlin, depois novos arquivos e funcionalidades. A interoperabilidade permite que Java e Kotlin coexistam no mesmo projeto indefinidamente.\nConversao de arquivos O IntelliJ IDEA oferece conversao automatica de arquivos Java para Kotlin. Use essa ferramenta como ponto de partida, mas sempre revise e refatore o código gerado para torna-lo idiomatico.\nProjetos novos em Kotlin Sempre que possível, proponha que novos projetos ou microsservicos sejam desenvolvidos em Kotlin desde o inicio. E mais fácil convencer equipes a experimentar em projetos greenfield.\nImpacto no salário A transicao para Kotlin pode ter impacto positivo no seu salário. Desenvolvedores que dominam tanto Java quanto Kotlin são particularmente valorizados porque entendem a interoperabilidade e podem liderar migracoes. No mercado brasileiro, a adoção de Kotlin no curriculo abre portas para fintechs e startups que oferecem remuneracoes acima da media.\nRecursos para a transicao A documentação oficial de Kotlin possui uma seção específica para desenvolvedores Java. O livro Kotlin in Action foi escrito pensando em profissionais Java. Os Kotlin Koans oferecem exercícios interativos que cobrem os conceitos essenciais. E os cursos da JetBrains Academy possuem trilhas dedicadas a transicao Java para Kotlin.\nConclusão A transicao de Java para Kotlin é uma das movimentacoes de carreira mais naturais e recompensadoras que um desenvolvedor JVM pode fazer. Com uma base solida de conhecimento transferivel, uma curva de aprendizado acessivel é um mercado que valoriza a linguagem, o investimento de tres a seis meses para dominar Kotlin pode resultar em melhores oportunidades, maior produtividade e satisfacao profissional no longo prazo. Outras transições populares para desenvolvedores JVM incluem migrar para Go, que atrai profissionais Java pela simplicidade, ou explorar Rust para projetos que exigem performance e segurança de memória.\n","permalink":"https://kotlin.dev.br/carreira/transicao-java-kotlin-carreira/","summary":"\u003ch2 id=\"transicao-de-java-para-kotlin-guia-completo-para-sua-carreira\"\u003eTransicao de Java para Kotlin: guia completo para sua carreira\u003c/h2\u003e\n\u003cp\u003eSe você é um desenvolvedor Java considerando a transicao para Kotlin, esta tomando uma decisao estrategica que pode impulsionar significativamente sua carreira. Kotlin foi projetado para ser uma evolução natural do Java, mantendo a interoperabilidade com a JVM enquanto oferece uma sintaxe mais moderna e produtiva. Este guia apresenta o caminho completo para fazer essa transicao de forma eficiente e estrategica.\u003c/p\u003e","title":"Transicao de Java para Kotlin: Guia de Carreira Completo | Kotlin Brasil"},{"content":"Compose Multiplatform da JetBrains levou o modelo declarativo do Jetpack Compose para além do Android. Com ele, você cria aplicativos desktop nativos para Windows, macOS e Linux usando Kotlin e os mesmos conceitos de UI que já domina no Android. Neste guia, vamos cobrir tudo que você precisa para começar a desenvolver aplicativos desktop com Compose Multiplatform.\nO que é Compose Multiplatform? Compose Multiplatform é um framework de UI declarativo da JetBrains que estende o Jetpack Compose do Google para rodar em múltiplas plataformas: Android, iOS, Desktop (JVM) e Web. No contexto desktop, a aplicação roda sobre a JVM e renderiza usando Skia, a mesma engine grafica usada pelo Chrome e Flutter.\nA proposta e clara: escrever UI uma vez em Kotlin e rodar em todas as plataformas. Embora cada plataforma tenha particularidades, a maior parte do código de interface e lógica pode ser compartilhada.\nConfiguração do projeto A maneira mais rápida de iniciar e usar o Kotlin Multiplatform Wizard da JetBrains ou o template oficial. Vamos configurar manualmente para entender cada parte.\nEstrutura do projeto meu-app-desktop/ build.gradle.kts settings.gradle.kts gradle.properties src/ main/ kotlin/ Main.kt resources/ icone.png build.gradle.kts import org.jetbrains.compose.desktop.application.dsl.TargetFormat plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.1.0\u0026#34; id(\u0026#34;org.jetbrains.compose\u0026#34;) version \u0026#34;1.7.3\u0026#34; id(\u0026#34;org.jetbrains.kotlin.plugin.compose\u0026#34;) version \u0026#34;2.1.0\u0026#34; } repositories { mavenCentral() maven(\u0026#34;https://maven.pkg.jetbrains.space/public/p/compose/dev\u0026#34;) } dependencies { implementation(compose.desktop.currentOs) implementation(compose.material3) } compose.desktop { application { mainClass = \u0026#34;MainKt\u0026#34; nativeDistributions { targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) packageName = \u0026#34;MeuApp\u0026#34; packageVersion = \u0026#34;1.0.0\u0026#34; } } } Ponto de entrada import androidx.compose.ui.window.Window import androidx.compose.ui.window.application fun main() = application { Window( onCloseRequest = ::exitApplication, title = \u0026#34;Meu App Desktop\u0026#34; ) { App() } } @Composable fun App() { MaterialTheme { var texto by remember { mutableStateOf(\u0026#34;\u0026#34;) } var itens by remember { mutableStateOf(listOf\u0026lt;String\u0026gt;()) } Column(modifier = Modifier.fillMaxSize().padding(16.dp)) { Text( text = \u0026#34;Gerenciador de Tarefas\u0026#34;, style = MaterialTheme.typography.headlineMedium ) Spacer(modifier = Modifier.height(16.dp)) Row(verticalAlignment = Alignment.CenterVertically) { OutlinedTextField( value = texto, onValueChange = { texto = it }, label = { Text(\u0026#34;Nova tarefa\u0026#34;) }, modifier = Modifier.weight(1f) ) Spacer(modifier = Modifier.width(8.dp)) Button(onClick = { if (texto.isNotBlank()) { itens = itens + texto texto = \u0026#34;\u0026#34; } }) { Text(\u0026#34;Adicionar\u0026#34;) } } Spacer(modifier = Modifier.height(16.dp)) LazyColumn { items(itens.size) { indice -\u0026gt; Card( modifier = Modifier .fillMaxWidth() .padding(vertical = 4.dp) ) { Row( modifier = Modifier.padding(16.dp), verticalAlignment = Alignment.CenterVertically ) { Text( text = itens[indice], modifier = Modifier.weight(1f) ) IconButton(onClick = { itens = itens.filterIndexed { i, _ -\u0026gt; i != indice } }) { Icon(Icons.Default.Delete, \u0026#34;Remover\u0026#34;) } } } } } } } } Para executar, use ./gradlew run no terminal.\nGerenciamento de janelas Compose Multiplatform oferece controle completo sobre janelas, incluindo tamanho, posicao, icone e comportamento.\nMultiplas janelas fun main() = application { var mostrarConfiguracoes by remember { mutableStateOf(false) } Window( onCloseRequest = ::exitApplication, title = \u0026#34;Janela Principal\u0026#34;, state = rememberWindowState( width = 800.dp, height = 600.dp ) ) { Column(modifier = Modifier.padding(16.dp)) { Text(\u0026#34;Janela Principal\u0026#34;) Button(onClick = { mostrarConfiguracoes = true }) { Text(\u0026#34;Abrir Configurações\u0026#34;) } } } if (mostrarConfiguracoes) { Window( onCloseRequest = { mostrarConfiguracoes = false }, title = \u0026#34;Configurações\u0026#34;, state = rememberWindowState( width = 400.dp, height = 300.dp ) ) { Text(\u0026#34;Painel de Configurações\u0026#34;, modifier = Modifier.padding(16.dp)) } } } Dialogo personalizado @Composable fun DialogoConfirmacao( titulo: String, mensagem: String, onConfirmar: () -\u0026gt; Unit, onCancelar: () -\u0026gt; Unit ) { Dialog( onCloseRequest = onCancelar, title = titulo, state = rememberDialogState(width = 350.dp, height = 200.dp) ) { Column( modifier = Modifier.fillMaxSize().padding(16.dp), verticalArrangement = Arrangement.SpaceBetween ) { Text(mensagem) Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End ) { TextButton(onClick = onCancelar) { Text(\u0026#34;Cancelar\u0026#34;) } Spacer(modifier = Modifier.width(8.dp)) Button(onClick = onConfirmar) { Text(\u0026#34;Confirmar\u0026#34;) } } } } } Menus nativos Aplicações desktop geralmente possuem barra de menus. Compose Multiplatform suporta menus nativos da plataforma:\nWindow( onCloseRequest = ::exitApplication, title = \u0026#34;Editor de Texto\u0026#34; ) { MenuBar { Menu(\u0026#34;Arquivo\u0026#34;) { Item(\u0026#34;Novo\u0026#34;, shortcut = KeyShortcut(Key.N, meta = true)) { println(\u0026#34;Novo arquivo\u0026#34;) } Item(\u0026#34;Abrir\u0026#34;, shortcut = KeyShortcut(Key.O, meta = true)) { println(\u0026#34;Abrir arquivo\u0026#34;) } Item(\u0026#34;Salvar\u0026#34;, shortcut = KeyShortcut(Key.S, meta = true)) { println(\u0026#34;Salvar arquivo\u0026#34;) } Separator() Item(\u0026#34;Sair\u0026#34;) { exitApplication() } } Menu(\u0026#34;Editar\u0026#34;) { Item(\u0026#34;Desfazer\u0026#34;, shortcut = KeyShortcut(Key.Z, meta = true)) {} Item(\u0026#34;Refazer\u0026#34;, shortcut = KeyShortcut(Key.Z, meta = true, shift = true)) {} } } // Conteudo da janela TextField( value = texto, onValueChange = { texto = it }, modifier = Modifier.fillMaxSize().padding(16.dp) ) } System Tray Você pode adicionar um icone na bandeja do sistema para que o app continue rodando em segundo plano:\nfun main() = application { var visivel by remember { mutableStateOf(true) } Tray( icon = painterResource(\u0026#34;icone.png\u0026#34;), tooltip = \u0026#34;Meu App\u0026#34;, menu = { Item(\u0026#34;Mostrar\u0026#34;) { visivel = true } Item(\u0026#34;Sair\u0026#34;) { exitApplication() } } ) if (visivel) { Window( onCloseRequest = { visivel = false }, title = \u0026#34;Meu App\u0026#34; ) { Text(\u0026#34;Feche a janela - o app continua na bandeja\u0026#34;) } } } Acesso a arquivos do sistema Diferente de aplicações mobile, apps desktop frequentemente precisam ler e escrever arquivos. Compose Multiplatform oferece dialogos de arquivo nativos:\n@Composable fun SeletorDeArquivo() { var caminhoArquivo by remember { mutableStateOf(\u0026#34;Nenhum arquivo selecionado\u0026#34;) } var conteudo by remember { mutableStateOf(\u0026#34;\u0026#34;) } Column(modifier = Modifier.padding(16.dp)) { Button(onClick = { val dialogo = FileDialog(ComposeWindow(), \u0026#34;Selecionar arquivo\u0026#34;, FileDialog.LOAD) dialogo.filenameFilter = FilenameFilter { _, nome -\u0026gt; nome.endsWith(\u0026#34;.txt\u0026#34;) } dialogo.isVisible = true val arquivo = dialogo.file val diretorio = dialogo.directory if (arquivo != null \u0026amp;\u0026amp; diretorio != null) { val path = File(diretorio, arquivo) caminhoArquivo = path.absolutePath conteudo = path.readText() } }) { Text(\u0026#34;Abrir Arquivo\u0026#34;) } Spacer(modifier = Modifier.height(8.dp)) Text(\u0026#34;Arquivo: $caminhoArquivo\u0026#34;) Spacer(modifier = Modifier.height(8.dp)) Text(conteudo) } } Atalhos de teclado Aplicações desktop dependem fortemente de atalhos de teclado para produtividade:\n@Composable fun EditorComAtalhos() { var texto by remember { mutableStateOf(\u0026#34;\u0026#34;) } var salvo by remember { mutableStateOf(false) } LaunchedEffect(Unit) { // Atalhos podem ser tratados via KeyEvent } Box( modifier = Modifier .fillMaxSize() .onPreviewKeyEvent { evento -\u0026gt; if (evento.isMetaPressed \u0026amp;\u0026amp; evento.key == Key.S \u0026amp;\u0026amp; evento.type == KeyEventType.KeyDown) { salvo = true true } else { false } } ) { Column(modifier = Modifier.padding(16.dp)) { if (salvo) { Text(\u0026#34;Arquivo salvo!\u0026#34;, color = MaterialTheme.colorScheme.primary) } TextField( value = texto, onValueChange = { texto = it salvo = false }, modifier = Modifier.fillMaxSize() ) } } } Distribuição do aplicativo Para distribuir seu app, o plugin Compose gera instaladores nativos para cada plataforma:\n# macOS: gera .dmg ./gradlew packageDmg # Windows: gera .msi ./gradlew packageMsi # Linux: gera .deb ./gradlew packageDeb Você pode personalizar metadados do instalador no build.gradle.kts:\ncompose.desktop { application { mainClass = \u0026#34;MainKt\u0026#34; nativeDistributions { targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) packageName = \u0026#34;MeuApp\u0026#34; packageVersion = \u0026#34;1.0.0\u0026#34; description = \u0026#34;Meu aplicativo desktop em Kotlin\u0026#34; vendor = \u0026#34;Minha Empresa\u0026#34; macOS { iconFile.set(project.file(\u0026#34;icone.icns\u0026#34;)) } windows { iconFile.set(project.file(\u0026#34;icone.ico\u0026#34;)) menuGroup = \u0026#34;Meus Apps\u0026#34; } linux { iconFile.set(project.file(\u0026#34;icone.png\u0026#34;)) } } } } Conclusão Compose Multiplatform para Desktop abre um caminho empolgante para desenvolvedores Kotlin que querem criar aplicações desktop modernas. A combinacao de UI declarativa, acesso completo a JVM e APIs nativas de cada sistema operacional resulta em uma experiência de desenvolvimento produtiva. Se você já conhece Jetpack Compose no Android, a transicao para desktop e quase imediata. O investimento em aprender Compose se multiplica: o mesmo conhecimento vale para Android, iOS, Desktop e Web. Para aplicações desktop que precisam de performance nativa máxima, Rust com frameworks como Tauri é outra opção que vale explorar.\n","permalink":"https://kotlin.dev.br/blog/kotlin-compose-multiplatform-desktop/","summary":"\u003cp\u003eCompose Multiplatform da JetBrains levou o modelo declarativo do Jetpack Compose para além do Android. Com ele, você cria aplicativos desktop nativos para Windows, macOS e Linux usando Kotlin e os mesmos conceitos de UI que já domina no Android. Neste guia, vamos cobrir tudo que você precisa para começar a desenvolver aplicativos desktop com Compose Multiplatform.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-compose-multiplatform\"\u003eO que é Compose Multiplatform?\u003c/h2\u003e\n\u003cp\u003eCompose Multiplatform é um framework de UI declarativo da JetBrains que estende o Jetpack Compose do Google para rodar em múltiplas plataformas: Android, iOS, Desktop (JVM) e Web. No contexto desktop, a aplicação roda sobre a JVM e renderiza usando Skia, a mesma engine grafica usada pelo Chrome e Flutter.\u003c/p\u003e","title":"Compose Multiplatform para Desktop: Guia Completo | Kotlin Brasil"},{"content":"Kotlin no mercado de trabalho em 2026: análise completa Kotlin deixou de ser a promessa do futuro para se tornar uma das linguagens mais relevantes do presente. Sua adoção no mercado de trabalho brasileiro e global atingiu patamares que a posicionam como uma escolha de carreira solida e com perspectivas de longo prazo. Este artigo apresenta uma análise aprofundada do mercado de trabalho para profissionais Kotlin em 2026.\nCrescimento da adoção de Kotlin O crescimento de Kotlin nos ultimos anos foi impulsionado por vários fatores convergentes. O suporte oficial do Google como linguagem preferida para Android criou uma base massiva de desenvolvedores. A adoção por empresas de grande porte para desenvolvimento backend validou a linguagem além do ecossistema mobile. E o amadurecimento do Kotlin Multiplatform abriu novas fronteiras de aplicação.\nEm pesquisas de popularidade de linguagens como o Stack Overflow Developer Survey é o TIOBE Index, Kotlin consistentemente aparece entre as linguagens mais amadas e com maior crescimento de adoção. No Brasil, a comunidade Kotlin cresceu de forma expressiva, com meetups regulares em diversas cidades é uma presenca cada vez maior em conferencias de tecnologia.\nDemanda por profissionais O volume de vagas que mencionam Kotlin no Brasil superou a marca de 15.000 posicoes abertas mensais em 2026. Esse número considera todas as plataformas de emprego e inclui vagas em diferentes niveis de experiência e especializacoes.\nA distribuição da demanda por area de atuacao é a seguinte:\nArea Percentual da Demanda Tendencia Android nativo 50% Estavel Backend/Server-side 30% Crescimento Multiplataforma 12% Crescimento acelerado DevOps/Automação 5% Crescimento Outras (data, scripts) 3% Emergente O dado mais significativo é o crescimento consistente da demanda por backend e multiplataforma, indicando que Kotlin esta se expandindo além de seu nicho original em Android.\nSetores com maior demanda Financeiro e fintechs O setor financeiro continua liderando a contratacao de desenvolvedores Kotlin. Bancos digitais, fintechs de pagamentos, credito e investimentos mantém equipes grandes de Kotlin tanto para aplicações mobile quanto para microsservicos backend. A segurança e confiabilidade proporcionadas pela null safety de Kotlin são particularmente valorizadas nesse setor.\nE-commerce e varejo digital Empresas de comercio eletronico dependem de aplicações mobile performaticas e backends escalaveis, duas areas onde Kotlin se destaca. O volume de transacoes mobile no Brasil cresce ano a ano, sustentando a demanda por profissionais.\nSaude digital Healthtechs representam um dos setores com maior crescimento de contratacao. Aplicações de telemedicina, prontuario eletronico e plataformas de saude utilizam Kotlin para garantir experiencias confiaveis para pacientes e profissionais de saude.\nLogistica e mobilidade Empresas de entrega, transporte e logistica investem pesadamente em tecnologia mobile e backend. A natureza em tempo real desses serviços demanda profissionais que dominem coroutines e programação assíncrona.\nEducacao Edtechs brasileiras adotaram Kotlin para suas plataformas, tanto em aplicações mobile para alunos quanto em sistemas backend de gestao educacional.\nFaixas salariais por especializacao O mercado remunera de forma diferenciada conforme a especializacao é o nível de experiência:\nEspecializacao Junior CLT Pleno CLT Senior CLT Android R$ 3.500 - R$ 6.000 R$ 7.000 - R$ 13.000 R$ 13.000 - R$ 22.000 Backend R$ 3.800 - R$ 6.500 R$ 7.500 - R$ 14.000 R$ 14.000 - R$ 24.000 Multiplatform R$ 4.000 - R$ 7.000 R$ 8.000 - R$ 15.000 R$ 15.000 - R$ 26.000 Profissionais que dominam Kotlin Multiplatform tendem a receber os maiores salários, refletindo a escassez de profissionais é a complexidade da especializacao.\nTendências que moldam o mercado Kotlin Multiplatform em producao A tecnologia Kotlin Multiplatform saiu do estagio experimental para producao. Empresas como Netflix, Cash App e diversas startups brasileiras utilizam KMP para compartilhar lógica de negócio entre plataformas. Essa tendencia cria uma nova categoria de vagas e valoriza profissionais com esse conhecimento. Para transformar essa tendência em plano de carreira, veja o guia de desenvolvedor Kotlin Multiplatform.\nCompose Multiplatform A extensao do Jetpack Compose para múltiplas plataformas, incluindo desktop e web, amplia o alcance de desenvolvedores Kotlin. Profissionais que dominam Compose podem criar interfaces para Android, iOS, desktop e web com uma única base de código.\nKotlin para scripts e automação O uso de Kotlin como linguagem de script para automação, build tools e infraestrutura como código esta crescendo. O Gradle Kotlin DSL é o exemplo mais evidente dessa tendencia, que abre oportunidades em areas adjacentes ao desenvolvimento tradicional.\nInteligencia artificial e machine learning Embora Python domine o cenário de IA e ML, Kotlin esta ganhando espaco em aplicações que integram modelos de machine learning em producao, especialmente no Android com TensorFlow Lite e em backends que servem modelos.\nComparação com outras linguagens no mercado Kotlin compete com diversas linguagens no mercado de trabalho brasileiro. Em relação ao Java, Kotlin oferece produtividade superior com salários equivalentes ou ligeiramente maiores. Comparado a Swift, Kotlin possui um mercado maior no Brasil devido a predominancia do Android. Em relação a Go e Rust no backend, Kotlin oferece uma transicao mais natural para desenvolvedores Java é um ecossistema mais maduro de frameworks web.\nDesafios do mercado Apesar do cenário favoravel, existem desafios. A oferta de profissionais junior qualificados não acompanha a demanda, criando dificuldade para empresas que não investem em formacao. A necessidade de ingles para acessar as melhores oportunidades remotas limita uma parcela dos profissionais. E a evolução rápida do ecossistema exige atualização constante.\nPerspectivas para os próximos anos O mercado de trabalho para Kotlin deve continuar em expansao nos próximos anos. A consolidacao do Kotlin Multiplatform, o crescimento do backend com Kotlin é a expansao para novas plataformas garantem relevancia de longo prazo. Profissionais que investem em especializacao e acompanham as tendências estarao bem posicionados para aproveitar as melhores oportunidades.\nConclusão Kotlin em 2026 é uma linguagem com mercado de trabalho robusto, diversificado e em crescimento. Com demanda superior a oferta, salários competitivos e perspectivas positivas, a carreira de desenvolvedor Kotlin oferece segurança e potencial de crescimento significativo. Seja no Android, backend ou multiplataforma, investir em Kotlin é uma decisao de carreira fundamentada em dados concretos do mercado.\n","permalink":"https://kotlin.dev.br/carreira/kotlin-mercado-trabalho/","summary":"\u003ch2 id=\"kotlin-no-mercado-de-trabalho-em-2026-análise-completa\"\u003eKotlin no mercado de trabalho em 2026: análise completa\u003c/h2\u003e\n\u003cp\u003eKotlin deixou de ser a promessa do futuro para se tornar uma das linguagens mais relevantes do presente. Sua adoção no mercado de trabalho brasileiro e global atingiu patamares que a posicionam como uma escolha de carreira solida e com perspectivas de longo prazo. Este artigo apresenta uma análise aprofundada do mercado de trabalho para profissionais Kotlin em 2026.\u003c/p\u003e\n\u003ch2 id=\"crescimento-da-adoção-de-kotlin\"\u003eCrescimento da adoção de Kotlin\u003c/h2\u003e\n\u003cp\u003eO crescimento de Kotlin nos ultimos anos foi impulsionado por vários fatores convergentes. O suporte oficial do Google como linguagem preferida para Android criou uma base massiva de desenvolvedores. A adoção por empresas de grande porte para desenvolvimento backend validou a linguagem além do ecossistema mobile. E o amadurecimento do Kotlin Multiplatform abriu novas fronteiras de aplicação.\u003c/p\u003e","title":"Kotlin no Mercado de Trabalho em 2026: Panorama Completo | Kotlin Brasil"},{"content":"Roadmap para desenvolvedor backend Kotlin em 2026 O backend é a espinha dorsal de qualquer aplicação moderna, e Kotlin se estabeleceu como uma das linguagens mais produtivas e elegantes para construir sistemas server-side. Com frameworks maduros como Spring Boot e Ktor, interoperabilidade com o vasto ecossistema Java e suporte nativo a coroutines, Kotlin oferece tudo o que um desenvolvedor backend precisa. Este roadmap apresenta o caminho completo do iniciante ao senior.\nPor que Kotlin no backend? Kotlin traz vantagens significativas em relação ao Java no desenvolvimento backend. A null safety elimina uma classe inteira de bugs comuns. A sintaxe concisa reduz a quantidade de código boilerplate. Coroutines oferecem programação assíncrona eficiente sem a complexidade de callbacks. E a interoperabilidade perfeita com Java permite aproveitar todo o ecossistema de bibliotecas existente.\nEmpresas como Amazon, Netflix, Square e diversas fintechs brasileiras já utilizam Kotlin em producao no backend, validando a maturidade da linguagem para sistemas de alta escala.\nFase 1: Fundamentos (2-3 meses) Kotlin essencial Domine a linguagem antes de se especializar em frameworks. Estude tipos e null safety, funções e higher-order functions, classes incluindo data classes, sealed classes e enum classes, coleções e programação funcional, generics e variancia, extension functions e tratamento de exceções.\nProgramação orientada a objetos e funcional Kotlin permite combinar paradigmas. Entenda quando usar orientacao a objetos e quando preferir abordagens funcionais. Estude principios SOLID e como aplicar em Kotlin.\nHTTP e APIs REST Antes de usar frameworks, entenda os fundamentos. Estude o protocolo HTTP incluindo métodos, status codes e headers. Aprenda sobre arquitetura REST e seus principios. Entenda formatos de dados como JSON e XML. E estude autenticação com tokens e JWT.\nFase 2: Primeiro framework (2-3 meses) Spring Boot com Kotlin Spring Boot é o framework mais utilizado no mercado brasileiro para backend Kotlin. Comece estudando a configuração de projetos com Spring Initializr e Gradle Kotlin DSL. Aprenda injeção de dependência e inversao de controle. Domine Spring MVC para criar controllers REST. Estude Spring Data JPA para acesso a bancos de dados relacionais. Configure Spring Security para autenticação e autorizacao. E aprenda sobre profiles e configuração externalizada.\nKtor como alternativa Ktor é o framework nativo de Kotlin criado pela JetBrains. E mais leve que Spring Boot e utiliza coroutines nativamente. Estude a arquitetura de plugins do Ktor, roteamento e serialização, autenticação e sessoes, é o cliente HTTP integrado. Ktor e particularmente indicado para microsservicos e aplicações que priorizam performance e simplicidade.\nBancos de dados Aprenda a trabalhar com bancos de dados relacionais, preferencialmente PostgreSQL. Estude SQL fundamental incluindo queries, joins, indices e transacoes. Aprenda Exposed, a biblioteca Kotlin da JetBrains para acesso a banco de dados, ou JPA com Hibernate. E pratique migrations com Flyway ou Liquibase. Para transformar essa etapa em projeto prático, siga o tutorial de Kotlin com PostgreSQL no backend.\nFase 3: Backend intermediário (3-4 meses) Coroutines para backend Aprofunde-se em coroutines aplicadas ao backend. Estude dispatchers e como escolher o correto para cada operação. Aprenda sobre structured concurrency e supervisao. Domine flows para streams de dados reativos. E entenda como coroutines se integram com Spring WebFlux ou Ktor.\nTestes Desenvolva uma cultura solida de testes. Escreva testes unitarios com JUnit 5 e MockK. Aprenda testes de integração com Testcontainers para subir dependências em containers. Pratique testes de API com RestAssured ou WebTestClient. E explore testes de contrato com Pact para validar integração entre serviços.\nBancos NoSQL Alem de bancos relacionais, aprenda ao menos um banco NoSQL. MongoDB é uma escolha popular para documentos. Redis e essencial para cache e sessoes. E Elasticsearch e valioso para busca textual e analytics.\nMensageria Estude sistemas de mensageria que são fundamentais em arquiteturas distribuidas. Apache Kafka é o padrão para event streaming de alta performance. RabbitMQ e excelente para filas de mensagens tradicionais. Entenda padrões como pub/sub, event sourcing e CQRS.\nFase 4: Backend avançado (3-6 meses) Arquitetura de microsservicos Estude padrões de microsservicos incluindo service discovery, API gateway, circuit breaker e saga. Aprenda sobre comunicação sincrona com REST e gRPC, e assíncrona com mensageria. Domine estrategias de deploy como blue-green e canary. E entenda observabilidade com métricas, logs e traces distribuidos.\nCloud e infraestrutura Aprenda ao menos um provedor de cloud em profundidade. AWS é o mais utilizado no Brasil, com serviços como EC2, ECS, Lambda, RDS, SQS e S3. Domine Docker para containerizacao de aplicações. Estude Kubernetes para orquestracao de containers. E aprenda Infrastructure as Code com Terraform ou CloudFormation.\nSegurança Aprofunde-se em segurança de aplicações backend. Estude OWASP Top 10 e como prevenir vulnerabilidades comuns. Aprenda sobre autenticação com OAuth2 e OpenID Connect. Domine criptografia e gerenciamento de segredos. E implemente rate limiting e proteção contra ataques.\nPerformance Aprenda a otimizar aplicações backend. Estude caching em múltiplas camadas. Domine profiling de aplicações JVM. Aprenda sobre connection pooling e otimização de queries. E implemente paginação eficiente e estrategias de lazy loading.\nFase 5: Senior e além (continuo) Design de sistemas Desenvolva a habilidade de projetar sistemas completos. Estude system design incluindo escalabilidade, disponibilidade e consistencia. Aprenda sobre padrões de resiliência como retry, timeout e fallback. E pratique documentação de arquitetura com C4 model e ADRs.\nLideranca técnica Conduza code reviews construtivos e eficientes. Defina padrões e guidelines para o time. Mentore desenvolvedores menos experientes. E participe de decisoes estrategicas de tecnologia.\nProjetos práticos recomendados Para iniciantes, construa uma API REST de CRUD com autenticação. Para intermediarios, crie um sistema de e-commerce com microsservicos. Para avançados, desenvolva uma plataforma de streaming de eventos com Kafka e processamento em tempo real. Publique todos os projetos no GitHub com documentação, testes e pipeline de CI/CD.\nConclusão O roadmap para desenvolvedor backend Kotlin em 2026 exige dedicacao consistente, mas oferece uma carreira com alta demanda e remuneracao atrativa. A combinacao de Kotlin com frameworks como Spring Boot e Ktor, bancos de dados, mensageria e cloud forma a base de um profissional completo e valorizado pelo mercado. Siga cada fase com prática constante e construa projetos reais para consolidar o aprendizado. Profissionais backend que também dominam Go para backend ou Rust no nicho web/backend se destacam ainda mais no mercado de microsserviços e sistemas de alta performance.\n","permalink":"https://kotlin.dev.br/carreira/roadmap-dev-backend-kotlin/","summary":"\u003ch2 id=\"roadmap-para-desenvolvedor-backend-kotlin-em-2026\"\u003eRoadmap para desenvolvedor backend Kotlin em 2026\u003c/h2\u003e\n\u003cp\u003eO backend é a espinha dorsal de qualquer aplicação moderna, e Kotlin se estabeleceu como uma das linguagens mais produtivas e elegantes para construir sistemas server-side. Com frameworks maduros como Spring Boot e Ktor, interoperabilidade com o vasto ecossistema Java e suporte nativo a coroutines, Kotlin oferece tudo o que um desenvolvedor backend precisa. Este roadmap apresenta o caminho completo do iniciante ao senior.\u003c/p\u003e","title":"Roadmap Desenvolvedor Backend Kotlin 2026: Guia Completo | Kotlin Brasil"},{"content":"Koin vs Dagger/Hilt em 2026: qual framework de DI escolher? A injeção de dependência é um padrão fundamental em aplicações Kotlin bem arquitetadas. Koin e Dagger (com seu wrapper Hilt) são as duas opções dominantes no ecossistema Android e Kotlin. Este artigo compara ambos os frameworks para ajudar você a escolher o mais adequado para seu projeto.\nVisao geral Caracteristica Koin Dagger/Hilt Tipo Service locator/DI em runtime DI em tempo de compilação Linguagem Kotlin-first Java (com suporte Kotlin) Validação Runtime Compilação Configuração DSL Kotlin Anotações Geracao de código Nao Sim (annotation processing) Curva de aprendizado Baixa Moderada a alta Google recomenda Nao oficialmente Sim (Hilt) Configuração e setup Koin utiliza uma DSL Kotlin intuitiva para definir modulos:\n// Modulos Koin val appModule = module { single\u0026lt;UsuarioRepository\u0026gt; { UsuarioRepositoryImpl(get()) } single\u0026lt;UsuarioService\u0026gt; { UsuarioServiceImpl(get()) } factory\u0026lt;BuscarUsuarioUseCase\u0026gt; { BuscarUsuarioUseCase(get()) } viewModel { UsuarioViewModel(get(), get()) } } val networkModule = module { single { Retrofit.Builder() .baseUrl(\u0026#34;https://api.exemplo.com/\u0026#34;) .addConverterFactory(Json.asConverterFactory(\u0026#34;application/json\u0026#34;.toMediaType())) .build() } single\u0026lt;UsuarioApi\u0026gt; { get\u0026lt;Retrofit\u0026gt;().create() } } // Inicialização class MeuApp : Application() { override fun onCreate() { super.onCreate() startKoin { androidContext(this@MeuApp) modules(appModule, networkModule) } } } // Uso no ViewModel class UsuarioViewModel( private val buscarUsuario: BuscarUsuarioUseCase, private val service: UsuarioService ) : ViewModel() { // ... } // Injeção em Composable @Composable fun TelaUsuarios(viewModel: UsuarioViewModel = koinViewModel()) { // ... } Dagger/Hilt utiliza anotações e geracao de código:\n// Modulos Hilt @Module @InstallIn(SingletonComponent::class) object NetworkModule { @Provides @Singleton fun provideRetrofit(): Retrofit = Retrofit.Builder() .baseUrl(\u0026#34;https://api.exemplo.com/\u0026#34;) .addConverterFactory(Json.asConverterFactory(\u0026#34;application/json\u0026#34;.toMediaType())) .build() @Provides @Singleton fun provideUsuarioApi(retrofit: Retrofit): UsuarioApi = retrofit.create(UsuarioApi::class.java) } @Module @InstallIn(SingletonComponent::class) abstract class RepositoryModule { @Binds @Singleton abstract fun bindUsuarioRepository( impl: UsuarioRepositoryImpl ): UsuarioRepository } // Inicialização @HiltAndroidApp class MeuApp : Application() // Uso no ViewModel @HiltViewModel class UsuarioViewModel @Inject constructor( private val buscarUsuario: BuscarUsuarioUseCase, private val service: UsuarioService ) : ViewModel() { // ... } // Injeção em Composable @Composable fun TelaUsuarios(viewModel: UsuarioViewModel = hiltViewModel()) { // ... } Koin requer menos código de configuração e a DSL e mais intuitiva. Hilt requer mais boilerplate mas oferece válidação em tempo de compilação.\nValidação de dependências Esta e uma das diferenças mais importantes. Dagger/Hilt válida todo o grafo de dependências em tempo de compilação. Se uma dependência estiver faltando, o projeto não compila. Isso previne erros de runtime.\nKoin válida dependências em runtime. Se uma dependência não estiver registrada, o erro só sera detectado quando a aplicação tentar resolve-la. O Koin oferece a função checkModules para verificar o grafo em testes, mas não e tao robusto quanto a válidação de compilação do Dagger.\n// Verificacao de modulos Koin em testes class VerificarModulosTest : KoinTest { @Test fun verificarTodosOsModulos() { koinApplication { modules(appModule, networkModule) checkModules() } } } Performance Aspecto Koin Dagger/Hilt Tempo de compilação Sem impacto Aumenta (annotation processing) Startup da app Ligeiramente mais lento Mais rápido Resolução de dependências Runtime (reflexao) Compilação (código gerado) Uso de memória Menor Similar Impacto em producao Negligivel Negligivel Na prática, a diferenca de performance entre ambos e negligivel para a maioria das aplicações. Dagger tem uma pequena vantagem teorica por resolver dependências em tempo de compilação, mas Koin e rápido o suficiente para aplicações de qualquer escala.\nTestes Koin facilita a substituicao de dependências em testes:\n@Test fun testComMock() { val mockRepository = mockk\u0026lt;UsuarioRepository\u0026gt;() loadKoinModules(module { single\u0026lt;UsuarioRepository\u0026gt; { mockRepository } }) // teste com mock } Hilt também oferece suporte a testes com substituicao de dependências:\n@HiltAndroidTest class UsuarioViewModelTest { @BindValue val mockRepository: UsuarioRepository = mockk() @Test fun testComMock() { // teste com mock } } Ambos os frameworks oferecem boa experiência de testes. Koin e mais flexivel para substituir dependências em tempo de teste, enquanto Hilt integra melhor com o framework de testes do Android.\nKotlin Multiplatform Koin suporta Kotlin Multiplatform nativamente, permitindo compartilhar a definicao de dependências entre Android, iOS, desktop e backend. Isso e uma vantagem significativa para projetos multiplataforma.\nDagger/Hilt e específico para Android e JVM, sem suporte a Kotlin Multiplatform.\nCurva de aprendizado Koin possui uma curva de aprendizado significativamente mais baixa. A DSL Kotlin e intuitiva e a documentação e clara. Um desenvolvedor pode aprender o básico em poucas horas.\nDagger/Hilt possui uma curva mais ingreme. Conceitos como Modules, Components, Scopes, Qualifiers e o fluxo de geracao de código requerem estudo mais aprofundado. O Hilt simplifica bastante o uso do Dagger, mas ainda exige mais aprendizado que o Koin.\nRecomendacao do Google O Google recomenda oficialmente o Hilt como solução de injeção de dependência para Android. Isso significa que exemplos oficiais, codelabs e documentação do Android utilizam Hilt. Essa recomendacao não invalida o Koin, mas significa que seguir Hilt resulta em maior alinhamento com o ecossistema oficial.\nCasos de uso recomendados Quando usar Koin Koin e ideal para projetos que priorizam simplicidade e velocidade de setup, aplicações Kotlin Multiplatform, equipes com desenvolvedores menos experientes em DI, protótipos e MVPs e projetos onde a DSL Kotlin e preferida a anotações.\nQuando usar Dagger/Hilt Hilt e ideal para projetos Android de grande escala, equipes que valorizam válidação em tempo de compilação, projetos que seguem as recomendações oficiais do Google, aplicações com grafos de dependência complexos e equipes com experiência em Dagger.\nVeredicto Em 2026, ambos os frameworks são opções solidas para injeção de dependência em projetos Kotlin. Koin brilha pela simplicidade, pela DSL Kotlin idiomatica e pelo suporte a multiplataforma. Hilt se destaca pela válidação em tempo de compilação, pela recomendacao oficial do Google e pela robustez em projetos de grande escala. Para a maioria dos projetos, a escolha e uma questao de preferencia da equipe. Para projetos multiplataforma, Koin e a escolha clara.\n","permalink":"https://kotlin.dev.br/comparacoes/koin-vs-dagger/","summary":"\u003ch2 id=\"koin-vs-daggerhilt-em-2026-qual-framework-de-di-escolher\"\u003eKoin vs Dagger/Hilt em 2026: qual framework de DI escolher?\u003c/h2\u003e\n\u003cp\u003eA injeção de dependência é um padrão fundamental em aplicações Kotlin bem arquitetadas. Koin e Dagger (com seu wrapper Hilt) são as duas opções dominantes no ecossistema Android e Kotlin. Este artigo compara ambos os frameworks para ajudar você a escolher o mais adequado para seu projeto.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracteristica\u003c/th\u003e\n          \u003cth\u003eKoin\u003c/th\u003e\n          \u003cth\u003eDagger/Hilt\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTipo\u003c/td\u003e\n          \u003ctd\u003eService locator/DI em runtime\u003c/td\u003e\n          \u003ctd\u003eDI em tempo de compilação\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eLinguagem\u003c/td\u003e\n          \u003ctd\u003eKotlin-first\u003c/td\u003e\n          \u003ctd\u003eJava (com suporte Kotlin)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eValidação\u003c/td\u003e\n          \u003ctd\u003eRuntime\u003c/td\u003e\n          \u003ctd\u003eCompilação\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eConfiguração\u003c/td\u003e\n          \u003ctd\u003eDSL Kotlin\u003c/td\u003e\n          \u003ctd\u003eAnotações\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eGeracao de código\u003c/td\u003e\n          \u003ctd\u003eNao\u003c/td\u003e\n          \u003ctd\u003eSim (annotation processing)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCurva de aprendizado\u003c/td\u003e\n          \u003ctd\u003eBaixa\u003c/td\u003e\n          \u003ctd\u003eModerada a alta\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eGoogle recomenda\u003c/td\u003e\n          \u003ctd\u003eNao oficialmente\u003c/td\u003e\n          \u003ctd\u003eSim (Hilt)\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"configuração-e-setup\"\u003eConfiguração e setup\u003c/h2\u003e\n\u003cp\u003eKoin utiliza uma DSL Kotlin intuitiva para definir modulos:\u003c/p\u003e","title":"Koin vs Dagger (Hilt): Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Roadmap completo para desenvolvedor Android em 2026 O desenvolvimento Android continua sendo uma das carreiras mais demandadas no mercado de tecnologia. Com Kotlin como linguagem oficial é o ecossistema Jetpack em constante evolução, o caminho para se tornar um desenvolvedor Android completo exige planejamento e dedicacao. Este roadmap apresenta uma trilha detalhada do zero ao nível senior, com tecnologias, recursos e cronogramas para cada etapa.\nFase 1: Fundamentos (2-3 meses) Logica de programação e algoritmos Antes de mergulhar no Android, garanta uma base solida em lógica de programação. Estude variaveis, tipos de dados e operadores. Domine estruturas condicionais e de repeticao. Aprenda funções e modularizacao de código. Pratique com exercícios em plataformas como URI Online Judge ou Beecrowd.\nKotlin básico Estude a sintaxe fundamental de Kotlin incluindo declaracao de variaveis com val e var, tipos básicos e inferencia de tipos, null safety e operadores de segurança, funções com parametros default e named arguments, classes e data classes, coleções e operações funcionais como map, filter e reduce, e tratamento de exceções.\nGit e controle de versão Aprenda os fundamentos de Git: init, add, commit, push, pull, branch e merge. Crie uma conta no GitHub e comece a versionar seus projetos desde o inicio.\nFase 2: Android básico (2-3 meses) Ambiente de desenvolvimento Instale e configure o Android Studio. Familiarize-se com a IDE, incluindo editor de código, emulador, Logcat, debugger e Gradle. Entenda a estrutura de um projeto Android.\nJetpack Compose fundamentals Jetpack Compose é o toolkit moderno e oficial para construcao de interfaces no Android. Comece pelos composables básicos como Text, Button, Image e Column. Aprenda sobre modificadores, layouts e temas. Estude gerenciamento de estado com remember e mutableStateOf. Pratique navegação entre telas com Navigation Compose. E explore listas com LazyColumn e LazyRow.\nDepois que o básico estiver confortável, crie um fluxo pequeno de CameraX com Jetpack Compose e Kotlin. Ele combina permissão, AndroidView, lifecycle, arquivo temporário e teste em aparelho físico — uma ótima ponte entre tutorial e app real.\nConceitos fundamentais do Android Entenda o ciclo de vida de Activities e como ele se aplica em Compose. Aprenda sobre Intents para navegação entre telas e comunicação entre componentes. Estude o sistema de permissoes do Android. E familiarize-se com recursos como strings, cores e dimensoes.\nFase 3: Android intermediário (3-4 meses) Arquitetura de aplicações Domine a arquitetura MVVM que é o padrão recomendado pelo Google. Aprenda sobre ViewModel e como ele sobrevive a mudancas de configuração. Estude StateFlow e SharedFlow para gerenciamento reativo de estado. Implemente repositórios para separar a lógica de dados da lógica de apresentação. E entenda Clean Architecture e como aplicar camadas de dominio, dados e apresentação.\nNetworking Aprenda a consumir APIs REST usando Retrofit com Kotlin. Estude serialização JSON com Moshi, Kotlinx Serialization ou Gson. Implemente tratamento de erros de rede, autenticação, paginação, retry e cache local. E pratique com APIs públicas para construir aplicações que exibem dados reais.\nPersistencia local Domine Room para banco de dados SQLite com Kotlin. Aprenda DataStore Preferences para preferências, filtros e dados simples. Estude estratégias de Android offline-first com Kotlin para aplicações que funcionam sem internet.\nInjeção de dependência Aprenda ao menos um framework de injeção de dependência. Hilt é a opção recomendada pelo Google e se integra nativamente com o ecossistema Jetpack. Koin é uma alternativa mais leve e com sintaxe Kotlin idiomatica.\nTestes Escreva testes unitários com JUnit e MockK. Aprenda testes de UI com Compose Testing. E pratique testes de integração para validar fluxos completos. Para organizar a sequência sem deixar a suíte lenta, siga o guia de testes Android com Kotlin, Compose e Maestro.\nFase 4: Android avançado (3-6 meses) Compose avançado Aprofunde-se em animacoes com Compose Animation API. Estude composables customizados e Canvas para desenho personalizado. Aprenda sobre performance e recomposicao inteligente. Domine temas avançados como CompositionLocal e efeitos colaterais.\nProgramação assíncrona avançada Domine coroutines em profundidade, incluindo structured concurrency, dispatchers, supervisao e cancelamento. Estude Flows avançados com operadores como combine, zip, flatMap e stateIn. E aprenda sobre testes de código assíncrono.\nFuncionalidades avançadas Implemente notificacoes push com Firebase Cloud Messaging. Aprenda WorkManager para tarefas em segundo plano, incluindo constraints, retry e sincronização offline-first. Estude deep linking e App Links com Kotlin para abrir telas reais a partir de web, e-mail e notificações. Pratique integração com serviços de localização. E explore CameraX para funcionalidades de camera.\nPerformance e otimização Aprenda a usar o Android Profiler para identificar gargalos. Estude otimização de memória e prevencao de vazamentos. Domine ferramentas de análise de performance de Compose. E aprenda sobre reducao do tamanho de APK com R8 e ProGuard.\nFase 5: Nível senior (continuo) Lideranca técnica Desenvolva habilidades de code review construtivo. Aprenda a documentar decisoes arquiteturais com ADRs. Pratique mentoria de desenvolvedores menos experientes. E participe de decisoes de produto além das tecnicas.\nKotlin Multiplatform Explore Kotlin Multiplatform para compartilhar lógica de negócio entre Android e iOS. Essa tecnologia esta em crescimento e representa um diferencial competitivo significativo. Se quiser seguir essa especialização, use o guia de desenvolvedor Kotlin Multiplatform como próxima trilha depois dos fundamentos avançados de Android.\nCI/CD e distribuição Configure pipelines de integração continua com GitHub Actions ou Bitrise. Automatize a distribuição de builds com Fastlane. E implemente estrategias de feature flags e lancamentos graduais.\nObservabilidade Implemente monitoramento com Firebase Crashlytics para Kotlin e Analytics. Estude ferramentas de APM como New Relic ou Datadog. E aprenda sobre logging estruturado, rastreamento de erros, ANRs e triagem por versão de app.\nProjetos práticos para cada fase Para a fase básica, construa uma calculadora é um aplicativo de lista de compras. Na fase intermediaria, crie um aplicativo de clima que consome API é um app de noticias com favoritos offline. Na fase avançada, desenvolva um aplicativo de chat em tempo real é um app de fitness com tracking de atividades. E para o nível senior, contribua para bibliotecas open source Android e construa uma biblioteca Compose reutilizavel.\nRecursos recomendados A documentação oficial do Android em developer.android.com é o recurso primario. Os codelabs do Google oferecem tutoriais práticos guiados. O canal Android Developers no YouTube traz novidades e tutoriais. E livros como Kotlin in Action e Android Programming with Kotlin completam a formacao teorica.\nCronograma resumido Do zero ao primeiro emprego como junior, o caminho leva tipicamente de 6 a 12 meses de estudo dedicado. De junior a pleno, a transicao leva de 2 a 4 anos de experiência profissional. E de pleno a senior, mais 2 a 4 anos com foco em profundidade técnica e lideranca.\nConclusão O roadmap para desenvolvedor Android em 2026 é um caminho desafiador mas recompensador. Com Kotlin como linguagem, Jetpack Compose como toolkit de UI é um ecossistema maduro de ferramentas e bibliotecas, o desenvolvedor Android moderno tem acesso a tecnologias de primeira classe. Siga este roadmap com consistencia, construa projetos reais e participe da comunidade para acelerar sua jornada profissional.\n","permalink":"https://kotlin.dev.br/carreira/roadmap-dev-android/","summary":"\u003ch2 id=\"roadmap-completo-para-desenvolvedor-android-em-2026\"\u003eRoadmap completo para desenvolvedor Android em 2026\u003c/h2\u003e\n\u003cp\u003eO desenvolvimento Android continua sendo uma das carreiras mais demandadas no mercado de tecnologia. Com Kotlin como linguagem oficial é o ecossistema Jetpack em constante evolução, o caminho para se tornar um desenvolvedor Android completo exige planejamento e dedicacao. Este roadmap apresenta uma trilha detalhada do zero ao nível senior, com tecnologias, recursos e cronogramas para cada etapa.\u003c/p\u003e\n\u003ch2 id=\"fase-1-fundamentos-2-3-meses\"\u003eFase 1: Fundamentos (2-3 meses)\u003c/h2\u003e\n\u003ch3 id=\"logica-de-programação-e-algoritmos\"\u003eLogica de programação e algoritmos\u003c/h3\u003e\n\u003cp\u003eAntes de mergulhar no Android, garanta uma base solida em lógica de programação. Estude variaveis, tipos de dados e operadores. Domine estruturas condicionais e de repeticao. Aprenda funções e modularizacao de código. Pratique com exercícios em plataformas como URI Online Judge ou Beecrowd.\u003c/p\u003e","title":"Roadmap Desenvolvedor Android 2026: Do Zero ao Senior | Kotlin Brasil"},{"content":"Certificacoes Kotlin: tudo o que você precisa saber em 2026 As certificacoes profissionais são uma forma eficaz de validar seus conhecimentos, destacar-se no mercado de trabalho e demonstrar comprometimento com o desenvolvimento profissional. No ecossistema Kotlin, existem opções de certificação que atendem diferentes perfis e especializacoes. Este guia completo apresenta todas as certificacoes relevantes para desenvolvedores Kotlin em 2026.\nKotlin Associate Certificate pela JetBrains A JetBrains, criadora do Kotlin, oferece o programa de certificação oficial que é a referência mais importante para profissionais da linguagem.\nSobre a certificação O Kotlin Associate Certificate é uma prova que avalia o conhecimento fundamental da linguagem Kotlin. A certificação válida que o profissional possui dominio solido da sintaxe, conceitos e boas práticas da linguagem. E administrada de forma online com supervisao remota.\nConteudo da prova A prova cobre os seguintes topicos: fundamentos da linguagem incluindo variaveis, tipos e operadores; estruturas de controle como if, when, for e while; funções incluindo parametros default, named arguments e higher-order functions; classes e objetos incluindo heranca, interfaces, data classes e sealed classes; null safety; coleções e operações funcionais; generics básicos; e tratamento de exceções.\nFormato e custo A prova e composta por questões de multipla escolha e questões práticas de código, com duracao de aproximadamente 90 minutos. O custo em 2026 gira em torno de USD 100 a USD 150. A certificação tem validade permanente, mas e recomendavel atualizar conforme novas versões da linguagem são lancadas.\nPreparacao Para se preparar, estude a documentação oficial de Kotlin, complete os Kotlin Koans e pratique exercícios no Hyperskill da JetBrains Academy. O livro Kotlin in Action também é um recurso excelente para consolidar os conhecimentos.\nGoogle Associate Android Developer Embora não seja exclusivamente de Kotlin, esta certificação do Google e altamente relevante para desenvolvedores Android que utilizam Kotlin.\nSobre a certificação A certificação válida a capacidade do profissional de desenvolver aplicações Android de qualidade. O exame inclui um projeto prático que deve ser desenvolvido em um prazo determinado, além de uma entrevista de saida.\nConteudo avaliado O exame cobre interface do usuário com Jetpack Compose e XML, navegação entre telas, persistencia de dados com Room, networking e integração com APIs, arquitetura de aplicações com MVVM, testes unitarios e de interface, e publicacao na Google Play Store.\nCusto e formato O custo da certificação e de USD 149. O exame combina um projeto prático com uma entrevista por video para validar que o candidato realmente desenvolveu o projeto. A certificação e reconhecida globalmente e tem peso significativo em processos seletivos.\nCertificacoes Spring Para desenvolvedores backend que utilizam Kotlin com Spring Boot, as certificacoes Spring da VMware são altamente valorizadas.\nSpring Certified Professional Esta certificação válida conhecimentos em Spring Framework e Spring Boot. Embora os exemplos oficiais sejam predominantemente em Java, a prova aceita conhecimentos aplicados em Kotlin. Custa aproximadamente USD 250 e cobre injeção de dependência, Spring MVC, Spring Data, segurança e configuração.\nPreparacao com Kotlin Se você pretende fazer a certificação Spring usando Kotlin, estude como os conceitos de Spring se aplicam especificamente em Kotlin, incluindo a configuração DSL, o uso de coroutines com WebFlux e as particularidades do Spring Boot com Kotlin.\nCertificacoes de cloud complementares Para desenvolvedores Kotlin que atuam no backend, certificacoes de cloud são complementos valiosos ao curriculo.\nAWS Certified Developer Associate Valida conhecimentos em serviços AWS relevantes para desenvolvedores, incluindo Lambda, DynamoDB, S3 e API Gateway. O custo e de USD 150 é a preparacao leva de dois a tres meses.\nGoogle Cloud Professional Cloud Developer Focada em desenvolvimento de aplicações na Google Cloud Platform. Particularmente relevante para quem trabalha com Kotlin no backend e utiliza serviços GCP.\nValor das certificacoes no mercado Impacto no salário Pesquisas indicam que profissionais certificados recebem em media 10 a 20 por cento a mais que profissionais sem certificação no mesmo nível de experiência. Para juniors, o impacto e ainda maior, pois a certificação compensa parcialmente a falta de experiência profissional.\nImpacto em processos seletivos Recrutadores e gestores de tecnologia consideram certificacoes como um indicador positivo de dedicacao e conhecimento. Embora não substituam a experiência prática, certificacoes podem ser o diferencial que coloca seu curriculo no topo da pilha em processos seletivos competitivos.\nCertificação versus experiência E importante ressaltar que certificacoes complementam, mas não substituem a experiência prática. O cenário ideal e combinar certificacoes com projetos reais, contribuicoes open source e experiência profissional. Um profissional com experiência e sem certificação geralmente e preferido a um profissional certificado mas sem experiência prática.\nComo se preparar de forma eficiente Estabeleca um cronograma Defina uma data para a prova e crie um cronograma de estudos retroativo. A maioria das certificacoes pode ser preparada em dois a tres meses com estudo regular de uma a duas horas por dia.\nUse recursos oficiais Comece sempre pelos materiais oficiais de preparacao. A documentação de Kotlin, os cursos da JetBrains Academy e os codelabs do Google são os recursos mais alinhados com o conteudo das provas.\nPratique com simulados Resolva questões de prática e simulados sempre que disponiveis. A familiaridade com o formato da prova reduz a ansiedade e melhora o desempenho no dia do exame.\nForme um grupo de estudos Estudar com outros profissionais que também estao se preparando para certificacoes é uma forma eficaz de manter a motivacao e esclarecer duvidas. Comunidades como a Kotlin Brasil frequentemente organizam grupos de estudo para certificacoes.\nRecomendações por perfil Para desenvolvedores Android junior, a combinacao do Kotlin Associate Certificate com o Google Associate Android Developer oferece uma base solida para iniciar a carreira. Para desenvolvedores backend, o Kotlin Associate Certificate combinado com uma certificação Spring é uma certificação de cloud forma um perfil altamente competitivo. Para profissionais em transicao de Java para Kotlin, iniciar pelo Kotlin Associate Certificate é o caminho mais direto para validar os novos conhecimentos.\nConclusão As certificacoes Kotlin e complementares representam um investimento acessivel com retorno significativo para sua carreira. Com custos que variam de USD 100 a USD 250 e preparacao de dois a tres meses, elas oferecem uma forma tangivel de demonstrar competencia e se diferenciar no mercado. Escolha as certificacoes alinhadas com seus objetivos de carreira, prepare-se com disciplina e utilize-as como parte de uma estrategia mais ampla de desenvolvimento profissional.\n","permalink":"https://kotlin.dev.br/carreira/certificacoes-kotlin/","summary":"\u003ch2 id=\"certificacoes-kotlin-tudo-o-que-você-precisa-saber-em-2026\"\u003eCertificacoes Kotlin: tudo o que você precisa saber em 2026\u003c/h2\u003e\n\u003cp\u003eAs certificacoes profissionais são uma forma eficaz de validar seus conhecimentos, destacar-se no mercado de trabalho e demonstrar comprometimento com o desenvolvimento profissional. No ecossistema Kotlin, existem opções de certificação que atendem diferentes perfis e especializacoes. Este guia completo apresenta todas as certificacoes relevantes para desenvolvedores Kotlin em 2026.\u003c/p\u003e\n\u003ch2 id=\"kotlin-associate-certificate-pela-jetbrains\"\u003eKotlin Associate Certificate pela JetBrains\u003c/h2\u003e\n\u003cp\u003eA JetBrains, criadora do Kotlin, oferece o programa de certificação oficial que é a referência mais importante para profissionais da linguagem.\u003c/p\u003e","title":"Certificacoes Kotlin: Guia Completo de Certificacoes em 2026 | Kotlin Brasil"},{"content":"Room vs SQLDelight em 2026: qual biblioteca de persistencia escolher? A persistencia de dados é um componente essencial em aplicações mobile e multiplataforma. Room e SQLDelight são as duas bibliotecas mais populares para trabalhar com SQLite em projetos Kotlin. Este artigo compara ambas em detalhes para ajudar você a escolher a mais adequada para seu projeto. Se sua decisão já aponta para multiplataforma, veja também o guia prático de SQLDelight com Kotlin Multiplatform.\nVisao geral Caracteristica Room SQLDelight Criador Google (Jetpack) Square / CashApp Abordagem ORM com anotações SQL-first com geracao de código Multiplataforma Somente Android Kotlin Multiplatform Coroutines Suporte nativo Suporte nativo Migração Automatica e manual Manual com SQL IDE Android Studio IntelliJ / Android Studio Abordagem fundamental Room utiliza uma abordagem ORM onde você define entidades como classes Kotlin e queries como métodos com anotações:\n@Entity(tableName = \u0026#34;usuarios\u0026#34;) data class UsuarioEntity( @PrimaryKey(autoGenerate = true) val id: Int = 0, val nome: String, val email: String, val dataCriacao: Long = System.currentTimeMillis() ) @Dao interface UsuarioDao { @Query(\u0026#34;SELECT * FROM usuarios ORDER BY nome ASC\u0026#34;) fun listarTodos(): Flow\u0026lt;List\u0026lt;UsuarioEntity\u0026gt;\u0026gt; @Query(\u0026#34;SELECT * FROM usuarios WHERE id = :id\u0026#34;) suspend fun buscarPorId(id: Int): UsuarioEntity? @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun inserir(usuario: UsuarioEntity) @Delete suspend fun deletar(usuario: UsuarioEntity) @Query(\u0026#34;SELECT * FROM usuarios WHERE nome LIKE \u0026#39;%\u0026#39; || :termo || \u0026#39;%\u0026#39;\u0026#34;) fun buscarPorNome(termo: String): Flow\u0026lt;List\u0026lt;UsuarioEntity\u0026gt;\u0026gt; } @Database(entities = [UsuarioEntity::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun usuarioDao(): UsuarioDao } SQLDelight utiliza uma abordagem SQL-first onde você escreve SQL puro em arquivos .sq e a biblioteca gera código Kotlin type-safe:\n-- Usuario.sq CREATE TABLE usuario ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, nome TEXT NOT NULL, email TEXT NOT NULL, data_criacao INTEGER NOT NULL DEFAULT 0 ); listarTodos: SELECT * FROM usuario ORDER BY nome ASC; buscarPorId: SELECT * FROM usuario WHERE id = ?; inserir: INSERT OR REPLACE INTO usuario (nome, email, data_criacao) VALUES (?, ?, ?); deletar: DELETE FROM usuario WHERE id = ?; buscarPorNome: SELECT * FROM usuario WHERE nome LIKE \u0026#39;%\u0026#39; || ? || \u0026#39;%\u0026#39;; O código gerado pelo SQLDelight oferece funções type-safe para cada query definida:\n// Uso do codigo gerado val database = Database(driver) val queries = database.usuarioQueries // Listar com Flow val usuarios: Flow\u0026lt;List\u0026lt;Usuario\u0026gt;\u0026gt; = queries.listarTodos() .asFlow() .mapToList(Dispatchers.IO) // Inserir queries.inserir( nome = \u0026#34;Maria\u0026#34;, email = \u0026#34;maria@email.com\u0026#34;, data_criacao = Clock.System.now().toEpochMilliseconds() ) Segurança de tipos Room válida queries SQL em tempo de compilação usando annotation processing. Erros em queries são detectados durante a compilação, o que é uma grande vantagem sobre acesso SQL manual. Porem, a válidação depende do schema definido pelas entidades anotadas.\nSQLDelight também válida SQL em tempo de compilação, mas vai além ao gerar modelos de dados diretamente a partir do schema SQL. Isso garante que o código Kotlin esta sempre sincronizado com o schema do banco de dados.\nPerformance Aspecto Room SQLDelight Overhead de abstracoes Baixo Minimo Geracao de código Annotation processing Gradle plugin Tempo de compilação Moderado Rapido Runtime overhead Pequeno (reflexao minima) Minimo Cache de queries Sim Sim Ambas as bibliotecas oferecem performance excelente. SQLDelight tende a ter um overhead ligeiramente menor por não utilizar reflexao e gerar código mais direto. Na prática, a diferenca e negligivel para a maioria das aplicações.\nKotlin Multiplatform Esta e a maior diferenca estrategica entre as duas bibliotecas. SQLDelight suporta Kotlin Multiplatform nativamente, permitindo compartilhar a camada de persistencia entre Android, iOS, desktop e backend com o mesmo código SQL.\nRoom e específico para Android e não oferece suporte a outras plataformas. Se você planeja compartilhar código entre plataformas, SQLDelight e a única opção entre as duas.\nMigracoes de schema Room oferece migracoes automaticas para mudancas simples e migracoes manuais para cenários complexos:\nval MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL(\u0026#34;ALTER TABLE usuarios ADD COLUMN telefone TEXT\u0026#34;) } } SQLDelight utiliza migracoes SQL puras em arquivos numerados:\n-- 1.sqm ALTER TABLE usuario ADD COLUMN telefone TEXT; Ambas as abordagens funcionam bem. Room oferece mais automação para migracoes simples, enquanto SQLDelight da controle total com SQL puro.\nIntegração com Jetpack Compose Ambas as bibliotecas se integram bem com Jetpack Compose através de Flow e collectAsState. A experiência e similar em ambos os casos, com dados reativos fluindo do banco para a UI de forma transparente.\nEcossistema e comunidade Room faz parte do Jetpack e possui documentação extensa, exemplos oficiais do Google e uma comunidade enorme. E a escolha padrão para a maioria dos projetos Android.\nSQLDelight possui documentação boa e uma comunidade ativa, embora menor. Sendo desenvolvido pela Square/CashApp, possui manutenção profissional e releases regulares.\nCasos de uso recomendados Quando usar Room Room e ideal para projetos exclusivamente Android, equipes familiarizadas com o ecossistema Jetpack, projetos que se beneficiam de migracoes automaticas e aplicações que precisam do suporte e documentação extensos do Google.\nQuando usar SQLDelight SQLDelight e ideal para projetos Kotlin Multiplatform que compartilham persistencia, equipes que preferem SQL puro a abstraccoes ORM, projetos que priorizam performance maxima e aplicações onde o controle total sobre queries e prioritario.\nVeredicto Em 2026, a escolha entre Room e SQLDelight depende principalmente de uma pergunta: seu projeto precisa de suporte multiplataforma? Se sim, SQLDelight e a escolha clara. Se não, ambas são excelentes, com Room oferecendo mais conveniencia e integração com o Jetpack, e SQLDelight oferecendo mais controle e performance marginal superior. Para novos projetos que podem eventualmente precisar de multiplataforma, SQLDelight e a escolha mais estrategica a longo prazo.\n","permalink":"https://kotlin.dev.br/comparacoes/room-vs-sqldelight/","summary":"\u003ch2 id=\"room-vs-sqldelight-em-2026-qual-biblioteca-de-persistencia-escolher\"\u003eRoom vs SQLDelight em 2026: qual biblioteca de persistencia escolher?\u003c/h2\u003e\n\u003cp\u003eA persistencia de dados é um componente essencial em aplicações mobile e multiplataforma. Room e SQLDelight são as duas bibliotecas mais populares para trabalhar com SQLite em projetos Kotlin. Este artigo compara ambas em detalhes para ajudar você a escolher a mais adequada para seu projeto. Se sua decisão já aponta para multiplataforma, veja também o guia prático de \u003ca href=\"/blog/sqldelight-kotlin-multiplatform-android-ios-2026/\"\u003eSQLDelight com Kotlin Multiplatform\u003c/a\u003e.\u003c/p\u003e","title":"Room vs SQLDelight: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Como se tornar um desenvolvedor Kotlin: guia completo para 2026 Kotlin se estabeleceu como uma das linguagens de programação mais relevantes do mercado, com aplicações em desenvolvimento Android, backend, multiplataforma e até ciencia de dados. Se você deseja iniciar ou migrar sua carreira para o desenvolvimento com Kotlin, este guia oferece um roadmap prático e detalhado para alcancar esse objetivo em 2026.\nPor que escolher Kotlin? Antes de começar sua jornada, é importante entender por que Kotlin é uma excelente escolha de carreira. A linguagem é a preferida pelo Google para desenvolvimento Android, utilizada por empresas como Netflix, Amazon e Pinterest em seus backends, suportada pela JetBrains com ferramentas de primeira classe, interoperavel com Java permitindo acesso a todo o ecossistema JVM, e cada vez mais adotada para desenvolvimento multiplataforma.\nO mercado brasileiro possui mais de 15.000 vagas mensais envolvendo Kotlin, com salários que variam de R$ 3.500 para juniors até mais de R$ 30.000 para seniors no regime PJ.\nPre-requisitos antes de começar Logica de programação Se você esta comecando do zero, o primeiro passo e aprender lógica de programação. Conceitos como variaveis, condicionais, lacos de repeticao, funções e estruturas de dados são fundamentais e independentes de linguagem. Existem cursos gratuitos em português em plataformas como Coursera, edX e YouTube que cobrem esses fundamentos.\nConhecimento básico de programação orientada a objetos Kotlin é uma linguagem multiparadigma, mas o dominio de orientacao a objetos e essencial. Entenda conceitos como classes, objetos, heranca, polimorfismo, encapsulamento e interfaces antes de se aprofundar em Kotlin.\nIngles técnico básico Grande parte da documentação de Kotlin, tutoriais avançados e recursos da comunidade estao em ingles. Um nível básico de leitura em ingles técnico acelerara significativamente seu aprendizado.\nRoadmap de estudos Fase 1: Fundamentos de Kotlin (1-2 meses) Comece pela sintaxe básica de Kotlin. Estude variaveis e tipos de dados, incluindo val e var, tipos básicos e inferencia de tipos. Aprenda sobre estruturas de controle como if, when, for e while. Domine funções, incluindo parametros default e named arguments. Estude null safety com tipos nulaveis, operador safe call e Elvis operator. Aprenda sobre coleções como List, Set e Map, e suas operações funcionais. E entenda classes e objetos, incluindo data classes, sealed classes, enum classes e companion objects.\nO site oficial kotlinlang.org oferece um tutorial interativo excelente chamado Kotlin Koans que cobre todos esses topicos. O curso oficial da JetBrains Academy também é uma otima opção.\nFase 2: Kotlin intermediário (1-2 meses) Aprofunde seus conhecimentos com extension functions, higher-order functions e lambdas. Estude generics e variancia. Aprenda sobre coroutines para programação assíncrona. Explore delegated properties e property delegation. Pratique tratamento de exceções e boas práticas. E comece a escrever testes unitarios com JUnit e MockK.\nFase 3: Escolha sua especializacao (2-3 meses) Neste ponto, você precisa decidir em qual area deseja se especializar.\nPara desenvolvimento Android, estude o Android SDK e seus componentes fundamentais, Activities, Fragments é o ciclo de vida. Aprenda Jetpack Compose para construcao de interfaces declarativas. Domine a arquitetura MVVM com ViewModel e LiveData ou StateFlow. Pratique integração com APIs REST usando Retrofit. E aprenda persistencia local com Room.\nPara desenvolvimento backend, estude Spring Boot com Kotlin ou Ktor. Aprenda sobre APIs REST e boas práticas de design. Domine integração com bancos de dados usando Exposed ou JPA. Pratique autenticação e autorizacao. E aprenda sobre testes de integração e deploy.\nFase 4: Projetos práticos (2-3 meses) A teoria sem prática não consolida o aprendizado. Construa projetos reais que demonstrem suas habilidades.\nPara Android, crie um aplicativo de lista de tarefas com persistencia local, um aplicativo que consuma uma API publica e exiba dados em lista, é um aplicativo de noticias com arquitetura Clean Architecture.\nPara backend, construa uma API REST completa com CRUD, autenticação e documentação, um sistema de gerenciamento com integração com banco de dados, é um microsservico com mensageria e cache.\nPublique todos os projetos no GitHub com README detalhado e código bem organizado.\nRecursos de estudo recomendados Gratuitos A documentação oficial de Kotlin em kotlinlang.org é o recurso mais completo e atualizado. O Kotlin Koans oferece exercícios interativos para praticar a sintaxe. O canal oficial da JetBrains no YouTube possui tutoriais em video. O curso Android Basics with Compose do Google e gratuito e abrangente. E o Hyperskill da JetBrains Academy possui trilhas gratuitas de Kotlin.\nPagos O livro Kotlin in Action é uma referência obrigatória para quem quer dominar a linguagem em profundidade. Cursos na Udemy e Alura oferecem conteudo estruturado em português. E a assinatura da JetBrains Academy oferece trilhas completas com projetos práticos.\nConstruindo seu portfolio Um portfolio solido é o que diferencia candidatos em processos seletivos. Mantenha um perfil ativo no GitHub com projetos bem documentados. Escreva artigos tecnicos sobre o que esta aprendendo em plataformas como Dev.to ou Medium. Contribua para projetos open source, mesmo que sejam pequenas correcoes ou melhorias na documentação. E participe de hackathons e desafios de programação.\nConseguindo seu primeiro emprego Prepare seu curriculo Destaque seus projetos práticos, tecnologias dominadas e qualquer experiência relevante. Mesmo projetos pessoais e contribuicoes open source contam como experiência.\nPratique para entrevistas Resolva problemas de algoritmos em plataformas como LeetCode e HackerRank. Pratique explicar suas decisoes tecnicas em voz alta. Revise conceitos de estruturas de dados e complexidade de algoritmos.\nCandidate-se estrategicamente Foque em vagas de nível júnior ou estágio. Candidate-se para programas de trainee de empresas de tecnologia. E não descarte empresas menores, onde você pode ter mais oportunidades de aprendizado e responsabilidade. Quando começar a enviar currículos de forma recorrente, use um sistema simples de acompanhamento; o guia do eu.dev.br sobre organizar candidaturas para vagas tech júnior é um bom complemento prático para essa etapa.\nFaca networking Participe de meetups e conferencias de Kotlin. Conecte-se com profissionais da area no LinkedIn. Participe ativamente de comunidades online como a Kotlin Brasil.\nConclusão Tornar-se um desenvolvedor Kotlin é uma jornada que exige dedicacao, mas oferece recompensas significativas. Com um mercado aquecido, salários atrativos é uma linguagem moderna e produtiva, a carreira de desenvolvedor Kotlin é uma das melhores escolhas no cenário de tecnologia brasileiro em 2026. Siga o roadmap apresentado, construa projetos práticos e participe da comunidade para acelerar sua transicao para essa carreira promissora. Para ampliar suas oportunidades, considere aprender também Go ou Python como linguagens complementares ao Kotlin.\n","permalink":"https://kotlin.dev.br/carreira/como-se-tornar-dev-kotlin/","summary":"\u003ch2 id=\"como-se-tornar-um-desenvolvedor-kotlin-guia-completo-para-2026\"\u003eComo se tornar um desenvolvedor Kotlin: guia completo para 2026\u003c/h2\u003e\n\u003cp\u003eKotlin se estabeleceu como uma das linguagens de programação mais relevantes do mercado, com aplicações em desenvolvimento Android, backend, multiplataforma e até ciencia de dados. Se você deseja iniciar ou migrar sua carreira para o desenvolvimento com Kotlin, este guia oferece um roadmap prático e detalhado para alcancar esse objetivo em 2026.\u003c/p\u003e\n\u003ch2 id=\"por-que-escolher-kotlin\"\u003ePor que escolher Kotlin?\u003c/h2\u003e\n\u003cp\u003eAntes de começar sua jornada, é importante entender por que Kotlin é uma excelente escolha de carreira. A linguagem é a preferida pelo Google para desenvolvimento Android, utilizada por empresas como Netflix, Amazon e Pinterest em seus backends, suportada pela JetBrains com ferramentas de primeira classe, interoperavel com Java permitindo acesso a todo o ecossistema JVM, e cada vez mais adotada para desenvolvimento multiplataforma.\u003c/p\u003e","title":"Como se Tornar um Desenvolvedor Kotlin em 2026 | Kotlin Brasil"},{"content":"Kotlin Multiplatform vs Flutter: desenvolvimento cross-platform em 2026 O desenvolvimento cross-platform continua sendo uma das decisoes mais impactantes para equipes de mobile. Kotlin Multiplatform (KMP) e Flutter representam filosofias fundamentalmente diferentes para resolver o mesmo problema: reduzir o custo de manter apps para múltiplas plataformas. Este artigo compara as duas abordagens em detalhes para ajudar você a tomar uma decisao informada.\nVisao geral Caracteristica Kotlin Multiplatform Flutter Empresa JetBrains Google Linguagem Kotlin Dart Compartilhamento Logica de negócio Tudo (lógica + UI) UI nativa Sim (SwiftUI/Compose) Propria (Skia/Impeller) Performance Nativa Quase nativa Maturidade Estavel desde 2023 Estavel desde 2018 Plataformas Android, iOS, Desktop, Web, Server Android, iOS, Web, Desktop Tamanho do app Similar ao nativo Maior (engine inclusa ~5-8MB) Filosofia de compartilhamento A diferenca mais importante entre KMP e Flutter esta na abordagem de compartilhamento.\nKotlin Multiplatform: compartilhe a lógica, mantenha UI nativa KMP permite compartilhar a lógica de negócio, acesso a dados, networking e validacoes entre plataformas, enquanto a UI permanece nativa em cada plataforma:\n// Código compartilhado (commonMain) class UsuarioRepositorio( private val api: UsuarioApi, private val banco: UsuarioBanco ) { suspend fun buscarUsuario(id: Int): Usuario { return try { val usuario = api.buscar(id) banco.salvar(usuario) usuario } catch (e: Exception) { banco.buscarLocal(id) ?: throw e } } suspend fun listar(): List\u0026lt;Usuario\u0026gt; { return api.listarTodos() } } // ViewModel compartilhado class ListaUsuariosViewModel( private val repositorio: UsuarioRepositorio ) : ViewModel() { private val _usuarios = MutableStateFlow\u0026lt;List\u0026lt;Usuario\u0026gt;\u0026gt;(emptyList()) val usuarios: StateFlow\u0026lt;List\u0026lt;Usuario\u0026gt;\u0026gt; = _usuarios.asStateFlow() fun carregar() { viewModelScope.launch { _usuarios.value = repositorio.listar() } } } A UI e implementada nativamente em cada plataforma:\n// Android - Jetpack Compose @Composable fun TelaUsuarios(viewModel: ListaUsuariosViewModel = koinViewModel()) { val usuarios by viewModel.usuarios.collectAsStateWithLifecycle() LazyColumn { items(usuarios) { usuario -\u0026gt; Text(usuario.nome) } } } // iOS - SwiftUI struct TelaUsuarios: View { @StateObject var viewModel = ListaUsuariosViewModel() var body: some View { List(viewModel.usuarios, id: \\.id) { usuario in Text(usuario.nome) } } } Flutter: compartilhe tudo Flutter compartilha lógica e UI. Um único codebase gera a interface para todas as plataformas:\n// Flutter: tudo compartilhado class TelaUsuarios extends StatefulWidget { @override _TelaUsuariosState createState() =\u0026gt; _TelaUsuariosState(); } class _TelaUsuariosState extends State\u0026lt;TelaUsuarios\u0026gt; { List\u0026lt;Usuario\u0026gt; usuarios = []; bool carregando = true; @override void initState() { super.initState(); carregarUsuarios(); } Future\u0026lt;void\u0026gt; carregarUsuarios() async { try { final resultado = await api.listarTodos(); setState(() { usuarios = resultado; carregando = false; }); } catch (e) { setState(() { carregando = false; }); } } @override Widget build(BuildContext context) { if (carregando) return CircularProgressIndicator(); return ListView.builder( itemCount: usuarios.length, itemBuilder: (context, index) { return ListTile(title: Text(usuarios[index].nome)); }, ); } } Performance Kotlin Multiplatform A lógica compartilhada KMP compila para código nativo em cada plataforma: JVM bytecode no Android e código nativo via Kotlin/Native no iOS. Nao há camada intermediaria de interpretacao. A UI, sendo nativa, renderiza com a performance maxima de cada plataforma.\nFlutter Flutter usa o motor grafico Impeller (substituto do Skia) para renderizar sua própria UI. A performance e excelente para a maioria dos casos, mas não e identica a UI nativa. Animacoes complexas e listas longas podem apresentar pequenas diferenças em comparação com componentes nativos, especialmente no iOS onde os usuários são sensiveis a detalhes de scroll e transicao.\nMetrica KMP Flutter Startup time Nativo +100-300ms (engine load) Memória base Nativa +20-40MB (engine) Animacoes Nativa (60/120fps) Impeller (60/120fps) Scroll feel Nativo perfeito Muito bom, quase nativo Tamanho APK minimo ~5MB ~12-15MB Experiência de desenvolvimento Ferramentas e IDE KMP usa IntelliJ IDEA ou Android Studio para o código compartilhado e Kotlin, e Xcode para a parte iOS nativa em Swift. Flutter usa qualquer editor com plugin (VS Code, Android Studio, IntelliJ), com hot reload que atualiza a UI em menos de um segundo.\nO hot reload do Flutter e uma vantagem significativa na velocidade de desenvolvimento de UI. KMP com Compose oferece preview no Android Studio, mas não tem hot reload tao rápido para iOS.\nCurva de aprendizado Para equipes que já desenvolvem Android com Kotlin, KMP tem uma curva de aprendizado menor porque a linguagem e as ferramentas são as mesmas. A parte iOS requer conhecimento de Swift/SwiftUI para a camada de UI.\nFlutter exige aprender Dart, que e uma linguagem acessivel mas menos popular que Kotlin. Porem, uma vez dominada, a equipe consegue entregar para todas as plataformas sem conhecimento de Swift ou Kotlin nativo.\nEcossistema e bibliotecas KMP O ecossistema KMP cresceu significativamente. Bibliotecas como Ktor (networking), SQLDelight (banco de dados), Koin (DI), kotlinx.serialization e kotlinx.datetime cobrem a maioria das necessidades. Alem disso, KMP permite usar qualquer biblioteca nativa de cada plataforma via expect/actual.\n// expect no commonMain expect class Plataforma() { val nome: String } // actual no androidMain actual class Plataforma { actual val nome: String = \u0026#34;Android ${Build.VERSION.SDK_INT}\u0026#34; } // actual no iosMain actual class Plataforma { actual val nome: String = UIDevice.currentDevice.systemName() } Flutter Flutter tem um ecossistema de pacotes enorme no pub.dev, com solucoes para praticamente qualquer necessidade. Porem, a qualidade varia significativamente entre pacotes da comunidade. Pacotes oficiais do Google (firebase, camera, maps) são bem mantidos, mas muitos pacotes de terceiros podem ficar desatualizados.\nIntegração com código nativo KMP A integração com código nativo e um ponto forte de KMP. No Android, você usa Kotlin diretamente. No iOS, o código compartilhado e exportado como framework e pode ser chamado de Swift sem nenhuma camada intermediaria.\nFlutter Flutter usa Platform Channels para comunicação com código nativo, o que adiciona uma camada de serialização e complexidade:\n// Flutter: Platform Channel static const platform = MethodChannel(\u0026#39;com.exemplo/nativo\u0026#39;); final resultado = await platform.invokeMethod(\u0026#39;buscarDadosBiometricos\u0026#39;); Essa abordagem funciona, mas e mais verbosa e propensa a erros do que a integração direta de KMP.\nQuando usar cada um Escolha Kotlin Multiplatform quando: Você tem equipes Android e iOS separadas que querem compartilhar lógica A experiência nativa da UI e prioridade absoluta O app precisa de integração profunda com APIs da plataforma A equipe Android já domina Kotlin Você quer adotar compartilhamento gradualmente (comece pela lógica, mantenha UI nativa) Escolha Flutter quando: Você tem uma equipe única para todas as plataformas Velocidade de entrega e mais importante que perfeicao nativa O design e customizado e não precisa seguir guidelines de cada plataforma Você quer hot reload para iteracao rápida na UI O projeto e um MVP ou prototipo que precisa ir ao ar rapidamente Veredito Em 2026, não há uma resposta universal. KMP e a escolha ideal quando a experiência nativa e inegociavel e você quer compartilhar lógica sem abrir mao do look and feel de cada plataforma. Flutter e a escolha quando produtividade maxima com uma única equipe e prioridade e você aceita pequenas diferenças na experiência nativa.\nA tendencia do mercado mostra KMP ganhando tracao em empresas que já investiram em Android com Kotlin, enquanto Flutter mantém dominio em startups e projetos que priorizam velocidade de entrega. Ambas as tecnologias são maduras e mantidas ativamente por grandes empresas, entao qualquer escolha e segura para o longo prazo. Se você está avaliando outras opções cross-platform, Python com Kivy também oferece desenvolvimento multiplataforma, enquanto Go permite compilar para múltiplas plataformas com binários nativos.\n","permalink":"https://kotlin.dev.br/comparacoes/kotlin-multiplatform-vs-flutter/","summary":"\u003ch2 id=\"kotlin-multiplatform-vs-flutter-desenvolvimento-cross-platform-em-2026\"\u003eKotlin Multiplatform vs Flutter: desenvolvimento cross-platform em 2026\u003c/h2\u003e\n\u003cp\u003eO desenvolvimento cross-platform continua sendo uma das decisoes mais impactantes para equipes de mobile. Kotlin Multiplatform (KMP) e Flutter representam filosofias fundamentalmente diferentes para resolver o mesmo problema: reduzir o custo de manter apps para múltiplas plataformas. Este artigo compara as duas abordagens em detalhes para ajudar você a tomar uma decisao informada.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracteristica\u003c/th\u003e\n          \u003cth\u003eKotlin Multiplatform\u003c/th\u003e\n          \u003cth\u003eFlutter\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eEmpresa\u003c/td\u003e\n          \u003ctd\u003eJetBrains\u003c/td\u003e\n          \u003ctd\u003eGoogle\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eLinguagem\u003c/td\u003e\n          \u003ctd\u003eKotlin\u003c/td\u003e\n          \u003ctd\u003eDart\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCompartilhamento\u003c/td\u003e\n          \u003ctd\u003eLogica de negócio\u003c/td\u003e\n          \u003ctd\u003eTudo (lógica + UI)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eUI nativa\u003c/td\u003e\n          \u003ctd\u003eSim (SwiftUI/Compose)\u003c/td\u003e\n          \u003ctd\u003ePropria (Skia/Impeller)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePerformance\u003c/td\u003e\n          \u003ctd\u003eNativa\u003c/td\u003e\n          \u003ctd\u003eQuase nativa\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eMaturidade\u003c/td\u003e\n          \u003ctd\u003eEstavel desde 2023\u003c/td\u003e\n          \u003ctd\u003eEstavel desde 2018\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePlataformas\u003c/td\u003e\n          \u003ctd\u003eAndroid, iOS, Desktop, Web, Server\u003c/td\u003e\n          \u003ctd\u003eAndroid, iOS, Web, Desktop\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTamanho do app\u003c/td\u003e\n          \u003ctd\u003eSimilar ao nativo\u003c/td\u003e\n          \u003ctd\u003eMaior (engine inclusa ~5-8MB)\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"filosofia-de-compartilhamento\"\u003eFilosofia de compartilhamento\u003c/h2\u003e\n\u003cp\u003eA diferenca mais importante entre KMP e Flutter esta na abordagem de compartilhamento.\u003c/p\u003e","title":"Kotlin Multiplatform vs Flutter: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Kotlin vs Rust em 2026: comparação entre duas linguagens modernas Kotlin e Rust são linguagens modernas que resolvem problemas diferentes com abordagens distintas. Kotlin foca em produtividade e segurança de tipos na JVM, enquanto Rust foca em performance e segurança de memória sem garbage collector. Este artigo analisa ambas as linguagens para ajudar você a entender onde cada uma brilha.\nVisao geral Caracteristica Kotlin Rust Criador JetBrains Mozilla (agora Rust Foundation) Gerenciamento de memória Garbage collector (JVM) Ownership system (sem GC) Performance Alta (JVM) Maxima (compilado nativo) Null safety Sistema de tipos Ownership + Option Concorrência Coroutines Fearless concurrency Curva de aprendizado Moderada Ingreme Principal uso Apps, backend, mobile Sistemas, CLI, WASM, backend Gerenciamento de memória A maior diferenca conceitual entre as linguagens esta no gerenciamento de memória.\nKotlin delega para o garbage collector da JVM:\nfun processarDados(): List\u0026lt;Resultado\u0026gt; { val dados = carregarDados() // alocado no heap val processados = dados.map { // nova lista no heap transformar(it) } return processados // dados original sera coletado pelo GC eventualmente } Rust utiliza o sistema de ownership com borrowing e lifetimes:\nfn processar_dados() -\u0026gt; Vec\u0026lt;Resultado\u0026gt; { let dados = carregar_dados(); // owner: esta funcao let processados: Vec\u0026lt;Resultado\u0026gt; = dados .iter() // borrow imutavel .map(|item| transformar(item)) .collect(); processados // dados e liberado automaticamente aqui (drop) } O modelo de Rust garante segurança de memória em tempo de compilação sem overhead de GC. O modelo de Kotlin e mais simples de usar mas possui pausas de garbage collection que podem impactar latencia em cenários criticos.\nPerformance Aspecto Kotlin (JVM) Rust Throughput Alto Muito alto Latencia Boa (pausas de GC) Consistente (sem GC) Uso de memória Moderado Minimo Startup Segundos Milissegundos Binario JAR + JVM Binario nativo Otimização JIT compiler LLVM (AOT) Rust oferece performance proxima a C e C++ sem sacrificar segurança. Kotlin na JVM oferece performance excelente para aplicações de negócio, mas não compete com Rust em cenários onde cada microsegundo importa.\nConcorrência Kotlin oferece coroutines como modelo principal:\nsuspend fun processarEmParalelo(itens: List\u0026lt;Item\u0026gt;): List\u0026lt;Resultado\u0026gt; = coroutineScope { itens.map { item -\u0026gt; async(Dispatchers.Default) { processar(item) } }.awaitAll() } Rust oferece fearless concurrency garantida pelo compilador:\nuse tokio; async fn processar_em_paralelo(itens: Vec\u0026lt;Item\u0026gt;) -\u0026gt; Vec\u0026lt;Resultado\u0026gt; { let handles: Vec\u0026lt;_\u0026gt; = itens .into_iter() .map(|item| tokio::spawn(async move { processar(item).await })) .collect(); let mut resultados = Vec::new(); for handle in handles { resultados.push(handle.await.unwrap()); } resultados } O sistema de ownership de Rust garante em tempo de compilação que não existem data races. Kotlin depende de convenções e boas práticas para evitar problemas de concorrência, embora coroutines reduzam significativamente os riscos.\nSegurança Ambas as linguagens priorizam segurança, mas em dimensoes diferentes.\nKotlin oferece null safety que elimina NullPointerException, smart casts que garantem tipos em tempo de compilação, e sealed classes para modelagem exaustiva de estados.\nRust oferece segurança de memória garantida sem GC, eliminacao de data races em tempo de compilação, sistema de tipos expressivo com Result e Option, e prevencao de use-after-free e buffer overflows.\nRust oferece garantias mais profundas de segurança, cobrindo memória, concorrência e recursos. Kotlin foca em segurança de tipos e nulabilidade, delegando segurança de memória para a JVM.\nEcossistema O ecossistema de Kotlin e vasto gracas a interoperabilidade com Java. Frameworks web como Spring Boot e Ktor, bibliotecas de banco de dados, ferramentas de teste e integração com serviços cloud estao amplamente disponiveis.\nO ecossistema de Rust cresce rapidamente. Actix-web e Axum são frameworks web performaticos. Tokio e o runtime assíncrono padrão. Serde e a biblioteca de serialização. E cargo e um gerenciador de pacotes exemplar. Porem, o ecossistema ainda e menor que o de Kotlin/JVM, especialmente em areas como integração com bancos de dados e serviços enterprise.\nCurva de aprendizado Kotlin possui uma curva de aprendizado moderada. Desenvolvedores Java ou de linguagens similares conseguem ser produtivos em semanas. A documentação e extensa e a comunidade e acolhedora.\nRust possui uma das curvas de aprendizado mais ingremes entre linguagens modernas. Conceitos como ownership, borrowing, lifetimes e o borrow checker representam um paradigma novo para a maioria dos desenvolvedores. O periodo para se tornar produtivo em Rust e significativamente maior.\nMercado de trabalho No Brasil, Kotlin possui um mercado significativamente maior que Rust. As vagas de Kotlin cobrem Android, backend e multiplataforma. Rust possui um mercado menor mas crescente, concentrado em infraestrutura, blockchain, ferramentas de desenvolvimento e sistemas embarcados.\nOs salários de Rust tendem a ser altos devido a escassez de profissionais, mas o volume de vagas e consideravelmente menor que o de Kotlin.\nCasos de uso recomendados Quando usar Kotlin Kotlin e ideal para aplicações mobile Android, APIs e microsservicos backend, aplicações multiplataforma, projetos com prazos apertados que priorizam produtividade e equipes que precisam de uma curva de aprendizado suave.\nQuando usar Rust Rust e ideal para sistemas que requerem latencia minima e previsivel, ferramentas de linha de comando e utilitarios de sistema, WebAssembly de alta performance, sistemas embarcados e IoT, e projetos onde segurança de memória e crítica.\nVeredicto Kotlin e Rust não são concorrentes diretos na maioria dos cenários. Kotlin e a escolha para desenvolvimento de aplicações e serviços onde produtividade e ecossistema são prioridades. Rust e a escolha para sistemas e infraestrutura onde performance maxima e segurança de memória são requisitos. Para quem quer se aprofundar em Rust, o rustlang.com.br oferece guias e glossário completos em português. Profissionais que dominam ambas as linguagens possuem um perfil extremamente raro e valorizado no mercado. Se o foco for backend com deploy simples e boa performance, Go é outra alternativa que vale explorar.\n","permalink":"https://kotlin.dev.br/comparacoes/kotlin-vs-rust/","summary":"\u003ch2 id=\"kotlin-vs-rust-em-2026-comparação-entre-duas-linguagens-modernas\"\u003eKotlin vs Rust em 2026: comparação entre duas linguagens modernas\u003c/h2\u003e\n\u003cp\u003eKotlin e Rust são linguagens modernas que resolvem problemas diferentes com abordagens distintas. Kotlin foca em produtividade e segurança de tipos na JVM, enquanto Rust foca em performance e segurança de memória sem garbage collector. Este artigo analisa ambas as linguagens para ajudar você a entender onde cada uma brilha.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracteristica\u003c/th\u003e\n          \u003cth\u003eKotlin\u003c/th\u003e\n          \u003cth\u003eRust\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCriador\u003c/td\u003e\n          \u003ctd\u003eJetBrains\u003c/td\u003e\n          \u003ctd\u003eMozilla (agora Rust Foundation)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eGerenciamento de memória\u003c/td\u003e\n          \u003ctd\u003eGarbage collector (JVM)\u003c/td\u003e\n          \u003ctd\u003eOwnership system (sem GC)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePerformance\u003c/td\u003e\n          \u003ctd\u003eAlta (JVM)\u003c/td\u003e\n          \u003ctd\u003eMaxima (compilado nativo)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eNull safety\u003c/td\u003e\n          \u003ctd\u003eSistema de tipos\u003c/td\u003e\n          \u003ctd\u003eOwnership + Option\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eConcorrência\u003c/td\u003e\n          \u003ctd\u003eCoroutines\u003c/td\u003e\n          \u003ctd\u003eFearless concurrency\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCurva de aprendizado\u003c/td\u003e\n          \u003ctd\u003eModerada\u003c/td\u003e\n          \u003ctd\u003eIngreme\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePrincipal uso\u003c/td\u003e\n          \u003ctd\u003eApps, backend, mobile\u003c/td\u003e\n          \u003ctd\u003eSistemas, CLI, WASM, backend\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"gerenciamento-de-memória\"\u003eGerenciamento de memória\u003c/h2\u003e\n\u003cp\u003eA maior diferenca conceitual entre as linguagens esta no gerenciamento de memória.\u003c/p\u003e","title":"Kotlin vs Rust: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Kotlin vs Go para backend em 2026: qual linguagem escolher? Kotlin e Go são duas das linguagens mais relevantes para desenvolvimento backend moderno, mas com filosofias diametralmente opostas. Kotlin oferece riqueza de funcionalidades e expressividade na JVM, enquanto Go prioriza simplicidade e eficiencia compilada. Este artigo compara as duas linguagens para ajudar na escolha do seu proximo projeto backend.\nVisao geral Caracteristica Kotlin (Backend) Go Criador JetBrains Google Plataforma JVM Compilado nativo Tipagem Estática rica Estática simples Concorrência Coroutines Goroutines Gerenciamento de memória Garbage collector (JVM) Garbage collector Startup time Moderado (JVM) Muito rápido Binario JAR (requer JVM) Binario único Ecossistema Vasto (JVM) Crescente Sintaxe e expressividade Kotlin oferece uma sintaxe rica e expressiva:\ndata class Usuario(val id: Int, val nome: String, val email: String) fun List\u0026lt;Usuario\u0026gt;.buscarPorDominio(dominio: String): List\u0026lt;Usuario\u0026gt; = filter { it.email.endsWith(\u0026#34;@$dominio\u0026#34;) } .sortedBy { it.nome } suspend fun processarUsuarios(usuarios: List\u0026lt;Usuario\u0026gt;): Map\u0026lt;String, List\u0026lt;Usuario\u0026gt;\u0026gt; = withContext(Dispatchers.Default) { usuarios.groupBy { it.email.substringAfter(\u0026#34;@\u0026#34;) } } Go prioriza simplicidade e legibilidade direta:\ntype Usuario struct { ID int `json:\u0026#34;id\u0026#34;` Nome string `json:\u0026#34;nome\u0026#34;` Email string `json:\u0026#34;email\u0026#34;` } func BuscarPorDominio(usuarios []Usuario, dominio string) []Usuario { var resultado []Usuario for _, u := range usuarios { if strings.HasSuffix(u.Email, \u0026#34;@\u0026#34;+dominio) { resultado = append(resultado, u) } } sort.Slice(resultado, func(i, j int) bool { return resultado[i].Nome \u0026lt; resultado[j].Nome }) return resultado } Kotlin permite escrever código mais conciso e expressivo com funcionalidades como extension functions, lambdas e operadores de colecao. Go exige mais linhas de código mas cada linha e imediatamente compreensivel sem conhecimento avançado da linguagem.\nConcorrência Ambas as linguagens oferecem modelos de concorrência modernos e eficientes.\nKotlin com coroutines:\nsuspend fun buscarDadosParalelos(): DadosCombinados = coroutineScope { val usuarios = async(Dispatchers.IO) { repositorio.buscarUsuarios() } val pedidos = async(Dispatchers.IO) { repositorio.buscarPedidos() } DadosCombinados( usuarios = usuarios.await(), pedidos = pedidos.await() ) } Go com goroutines e channels:\nfunc BuscarDadosParalelos() DadosCombinados { chUsuarios := make(chan []Usuario) chPedidos := make(chan []Pedido) go func() { chUsuarios \u0026lt;- repositorio.BuscarUsuarios() }() go func() { chPedidos \u0026lt;- repositorio.BuscarPedidos() }() return DadosCombinados{ Usuarios: \u0026lt;-chUsuarios, Pedidos: \u0026lt;-chPedidos, } } Goroutines são extremamente leves e Go foi projetado em torno desse modelo. Coroutines de Kotlin são igualmente eficientes e oferecem mais ferramentas como structured concurrency e flow para streams reativos.\nPerformance Aspecto Kotlin (JVM) Go Startup time 3-15 segundos Milissegundos Uso de memória base 100-300 MB 10-30 MB Throughput HTTP Alto Alto Latencia Baixa (apos warmup) Consistentemente baixa Compilação Moderada Muito rápida Binario/Deploy JAR + JVM Binario único Go tem vantagens claras em startup time, uso de memória e simplicidade de deploy. Kotlin na JVM oferece throughput competitivo apos o warmup da JVM e se beneficia das otimizações do JIT compiler para aplicações de longa duracao.\nPara funções serverless e containers efemeros, Go e significativamente superior. Para aplicações de longa duracao com alto throughput, a diferenca e menor.\nEcossistema Kotlin tem acesso a todo o ecossistema JVM, que e o mais rico da industria. Spring Boot, Hibernate, Apache Kafka, Elasticsearch e milhares de bibliotecas maduras estao disponiveis. Alem disso, Kotlin possui frameworks nativos como Ktor e Exposed.\nGo possui um ecossistema mais enxuto mas que cobre as necessidades mais comuns para desenvolvimento backend. A biblioteca padrão de Go e excepcionalmente completa, incluindo servidor HTTP, cliente HTTP, encoding JSON e ferramentas de teste sem dependências externas.\nDeploy e operações Go produz binarios estaticos que não requerem runtime externo. Um serviço Go pode ser empacotado em uma imagem Docker minima de poucos megabytes. Isso simplifica o deploy e reduz custos de infraestrutura.\nKotlin na JVM requer a maquina virtual Java, resultando em imagens Docker maiores e maior consumo de memória. GraalVM Native Image pode mitigar isso compilando Kotlin para binarios nativos, mas o suporte ainda tem limitações com reflexao e bibliotecas que dependem de features dinamicas da JVM.\nMercado de trabalho No Brasil, Kotlin backend possui mais vagas que Go, especialmente em empresas que já utilizam o ecossistema JVM. Go cresce rapidamente em empresas de infraestrutura, cloud e startups que priorizam performance e simplicidade.\nOs salários de Go tendem a ser competitivos com os de Kotlin, e a demanda por profissionais Go cresce consistentemente.\nCasos de uso recomendados Quando usar Kotlin Kotlin backend e ideal quando a equipe já possui expertise JVM, o projeto precisa de integração com ecossistema Java existente, complexidade de dominio justifica expressividade da linguagem, e a aplicação e de longa duracao com alto throughput.\nQuando usar Go Go e ideal para microsservicos com requisitos de baixa latencia, funções serverless e aplicações efemeras, ferramentas de CLI e utilitarios de infraestrutura, sistemas que precisam de deploy simples e consumo minimo de recursos, e projetos com equipes grandes onde a simplicidade da linguagem facilita a manutenção.\nVeredicto A escolha entre Kotlin e Go para backend em 2026 depende das prioridades do projeto. Kotlin oferece mais expressividade, um ecossistema maior e melhor integração com sistemas JVM existentes. Go oferece simplicidade, performance previsivel e deploy mais eficiente. Para se aprofundar no ecossistema Go, confira o portal Go em português no golang.com.br. Ambas são excelentes escolhas para backend moderno, e a decisao deve considerar a expertise da equipe, os requisitos de infraestrutura e a complexidade do dominio. Se performance maxima sem garbage collector for prioridade, vale também conhecer Rust para backend.\n","permalink":"https://kotlin.dev.br/comparacoes/kotlin-vs-go-backend/","summary":"\u003ch2 id=\"kotlin-vs-go-para-backend-em-2026-qual-linguagem-escolher\"\u003eKotlin vs Go para backend em 2026: qual linguagem escolher?\u003c/h2\u003e\n\u003cp\u003eKotlin e Go são duas das linguagens mais relevantes para desenvolvimento backend moderno, mas com filosofias diametralmente opostas. Kotlin oferece riqueza de funcionalidades e expressividade na JVM, enquanto Go prioriza simplicidade e eficiencia compilada. Este artigo compara as duas linguagens para ajudar na escolha do seu proximo projeto backend.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracteristica\u003c/th\u003e\n          \u003cth\u003eKotlin (Backend)\u003c/th\u003e\n          \u003cth\u003eGo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCriador\u003c/td\u003e\n          \u003ctd\u003eJetBrains\u003c/td\u003e\n          \u003ctd\u003eGoogle\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePlataforma\u003c/td\u003e\n          \u003ctd\u003eJVM\u003c/td\u003e\n          \u003ctd\u003eCompilado nativo\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTipagem\u003c/td\u003e\n          \u003ctd\u003eEstática rica\u003c/td\u003e\n          \u003ctd\u003eEstática simples\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eConcorrência\u003c/td\u003e\n          \u003ctd\u003eCoroutines\u003c/td\u003e\n          \u003ctd\u003eGoroutines\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eGerenciamento de memória\u003c/td\u003e\n          \u003ctd\u003eGarbage collector (JVM)\u003c/td\u003e\n          \u003ctd\u003eGarbage collector\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eStartup time\u003c/td\u003e\n          \u003ctd\u003eModerado (JVM)\u003c/td\u003e\n          \u003ctd\u003eMuito rápido\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eBinario\u003c/td\u003e\n          \u003ctd\u003eJAR (requer JVM)\u003c/td\u003e\n          \u003ctd\u003eBinario único\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eEcossistema\u003c/td\u003e\n          \u003ctd\u003eVasto (JVM)\u003c/td\u003e\n          \u003ctd\u003eCrescente\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"sintaxe-e-expressividade\"\u003eSintaxe e expressividade\u003c/h2\u003e\n\u003cp\u003eKotlin oferece uma sintaxe rica e expressiva:\u003c/p\u003e","title":"Kotlin vs Go para Backend: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Vagas de Kotlin no Brasil em 2026: um mercado em expansao O ecossistema de Kotlin no Brasil atingiu um nível de maturidade que o posiciona como uma das linguagens mais demandadas no mercado de trabalho nacional. Empresas de todos os setores, desde fintechs até o agronegocio, buscam desenvolvedores que dominam Kotlin para construir aplicações mobile, backend e multiplataforma. Este artigo apresenta um panorama completo das vagas de Kotlin no Brasil em 2026.\nNumeros do mercado O volume de vagas que mencionam Kotlin como requisito ou diferencial cresceu consistentemente nos ultimos anos. Em 2026, estima-se que existam mais de 15.000 posicoes abertas por mes no Brasil que envolvem desenvolvimento com Kotlin, considerando todas as plataformas e fontes de vagas. Desse total, aproximadamente 55 por cento são focadas em desenvolvimento Android, 30 por cento em backend e 15 por cento em posicoes multiplataforma ou full-stack.\nSetores que mais contratam Financeiro e fintechs O setor financeiro lidera a contratacao de desenvolvedores Kotlin no Brasil. Bancos digitais como Nubank, C6 Bank, Inter e PicPay possuem equipes grandes de desenvolvimento Kotlin. Bancos tradicionais como Itau, Bradesco e Santander também migraram suas aplicações mobile para Kotlin e mantém equipes dedicadas. Fintechs menores e em crescimento complementam o cenário com vagas frequentes.\nE-commerce e marketplaces Mercado Livre, Magazine Luiza, Americanas e Amazon Brasil são exemplos de empresas de comercio eletronico com grande demanda por desenvolvedores Kotlin. O volume de transacoes mobile nessas plataformas exige equipes robustas de desenvolvimento Android.\nDelivery e mobilidade iFood, Rappi, 99 e empresas de logistica investem pesadamente em desenvolvimento mobile e backend com Kotlin. A natureza do serviço, que depende de aplicativos funcionando de forma impecavel, gera demanda constante por profissionais qualificados.\nSaude e healthtechs O setor de saude digital cresceu exponencialmente e empresas como Dr. Consulta, Alice e Conexa Saude utilizam Kotlin em suas plataformas. Vagas nesse setor oferecem a combinacao de bons salários e proposito.\nEducacao e edtechs Plataformas educacionais como Descomplica, Quero Educacao e Arco Educacao mantém equipes de desenvolvimento Kotlin para suas aplicações mobile e backend.\nPrincipais regioes e polos tecnologicos São Paulo A capital paulista e seu entorno concentram a maior parte das vagas de Kotlin no Brasil. A presenca de sedes de grandes empresas de tecnologia, fintechs e corporacoes faz de São Paulo o polo com maior volume de oportunidades e os salários mais elevados. A região de Pinheiros, Vila Olimpia e Faria Lima concentra um número expressivo de empresas de tecnologia.\nCampinas e interior de SP O polo tecnologico de Campinas, que inclui cidades como Jundiai e Sorocaba, possui empresas como CI\u0026amp;T, CPQD e diversas startups que contratam desenvolvedores Kotlin regularmente.\nFlorianopolis A ilha de Santa Catarina se consolidou como um dos principais polos de tecnologia do Brasil. Empresas como RD Station, Involves e diversas startups oferecem vagas de Kotlin com remuneracao competitiva e qualidade de vida diferenciada.\nRecife e Porto Digital O Porto Digital em Recife é um dos maiores parques tecnologicos do Brasil, abrigando mais de 300 empresas de tecnologia. A demanda por desenvolvedores Kotlin na região cresce ano a ano.\nBelo Horizonte A capital mineira possui um ecossistema de startups vibrante, com empresas como Hotmart, Rock Content e Take Blip contratando profissionais Kotlin.\nCuritiba e Porto Alegre Ambas as capitais possuem polos tecnologicos relevantes com vagas consistentes para desenvolvedores Kotlin em empresas de software e consultoria.\nTipos de contratacao mais comuns O mercado brasileiro de Kotlin oferece diferentes modalidades de contratacao:\nModalidade Caracteristicas Percentual de Vagas CLT Beneficios completos, estabilidade 45% PJ Maior remuneracao bruta, flexibilidade 35% Cooperativa Modelo intermediário 10% Freelance/Projeto Por demanda 10% A tendencia e de equilibrio entre CLT e PJ, com empresas oferecendo ambas as opções para atrair diferentes perfis de profissionais.\nProcesso seletivo tipico O processo seletivo para vagas de Kotlin no Brasil geralmente segue um fluxo estruturado. Comeca com uma triagem de curriculo, seguida por uma entrevista com o time de recursos humanos para alinhamento cultural e expectativas. A proxima etapa geralmente envolve um teste técnico, que pode ser um desafio de código para ser resolvido em casa ou uma sessao de live coding. Depois vem a entrevista técnica com membros do time de desenvolvimento, onde são avaliados conhecimentos em Kotlin, arquitetura e resolução de problemas. Algumas empresas incluem uma etapa final com o gestor da area.\nPara se preparar, pratique algoritmos e estruturas de dados, revise conceitos de arquitetura de software e esteja pronto para discutir projetos anteriores em detalhes.\nDicas para encontrar as melhores vagas Mantenha seu LinkedIn atualizado e ativo, pois grande parte dos recrutadores utiliza a plataforma para identificar candidatos. Cadastre-se em plataformas especializadas como Geek Hunter e Programathor. Para quem ainda está mirando primeira vaga, estágio ou oportunidade júnior em tecnologia, vale acompanhar também o painel de vagas júnior do eu.dev.br, porque ele filtra oportunidades de entrada sem prender a busca a uma única linguagem. Participe de comunidades Kotlin no Brasil, onde vagas são compartilhadas frequentemente. Acompanhe as páginas de carreira das empresas que você admira. E considere trabalhar com recrutadores especializados em tecnologia, que podem apresentar oportunidades exclusivas.\nTendências para os próximos anos A demanda por desenvolvedores Kotlin no Brasil deve continuar crescendo impulsionada pela adoção de Kotlin Multiplatform, pela migração continua de projetos Java para Kotlin no backend e pelo crescimento do mercado de aplicativos mobile. Profissionais que se mantém atualizados e investem em especializacao estarao bem posicionados para aproveitar esse cenário favoravel.\nConclusão O mercado de vagas de Kotlin no Brasil em 2026 e robusto e diversificado, com oportunidades em praticamente todos os setores da economia digital. Com mais de 15.000 posicoes abertas mensalmente, faixas salariais atrativas e perspectivas positivas de crescimento, a carreira de desenvolvedor Kotlin no Brasil oferece estabilidade e potencial de evolução profissional significativo. Se você também quer explorar oportunidades em outras linguagens backend, confira as vagas de Go no Brasil e as vagas de Python.\n","permalink":"https://kotlin.dev.br/carreira/vagas-kotlin-brasil/","summary":"\u003ch2 id=\"vagas-de-kotlin-no-brasil-em-2026-um-mercado-em-expansao\"\u003eVagas de Kotlin no Brasil em 2026: um mercado em expansao\u003c/h2\u003e\n\u003cp\u003eO ecossistema de Kotlin no Brasil atingiu um nível de maturidade que o posiciona como uma das linguagens mais demandadas no mercado de trabalho nacional. Empresas de todos os setores, desde fintechs até o agronegocio, buscam desenvolvedores que dominam Kotlin para construir aplicações mobile, backend e multiplataforma. Este artigo apresenta um panorama completo das vagas de Kotlin no Brasil em 2026.\u003c/p\u003e","title":"Vagas Kotlin no Brasil: Mercado, Empresas e Oportunidades em 2026 | Kotlin Brasil"},{"content":"Ktor vs Spring Boot em 2026: qual framework backend escolher? A escolha do framework backend é uma das decisoes mais impactantes em um projeto Kotlin. Ktor e Spring Boot são as duas opções dominantes, cada uma com filosofia e pontos fortes distintos. Ktor é o framework nativo de Kotlin criado pela JetBrains, enquanto Spring Boot é o gigante do ecossistema Java que oferece suporte completo a Kotlin. Este artigo compara ambos em profundidade.\nVisao geral Caracteristica Ktor Spring Boot Criador JetBrains VMware (Pivotal) Filosofia Leve e modular Full-featured e opinado Coroutines Nativo Suportado Tamanho do framework Pequeno Grande Ecossistema Crescente Massivo Curva de aprendizado Baixa Moderada a alta Mercado de trabalho Crescente Dominante Configuração e estrutura do projeto Ktor utiliza uma abordagem minimalista baseada em plugins:\nfun main() { embeddedServer(Netty, port = 8080) { install(ContentNegotiation) { json() } install(StatusPages) { exception\u0026lt;Throwable\u0026gt; { call, cause -\u0026gt; call.respondText( text = cause.localizedMessage, status = HttpStatusCode.InternalServerError ) } } routing { get(\u0026#34;/usuarios\u0026#34;) { val usuarios = usuarioService.listarTodos() call.respond(usuarios) } post(\u0026#34;/usuarios\u0026#34;) { val usuario = call.receive\u0026lt;CriarUsuarioRequest\u0026gt;() val criado = usuarioService.criar(usuario) call.respond(HttpStatusCode.Created, criado) } } }.start(wait = true) } Spring Boot utiliza anotações e inversao de controle:\n@RestController @RequestMapping(\u0026#34;/usuarios\u0026#34;) class UsuarioController( private val usuarioService: UsuarioService ) { @GetMapping fun listarTodos(): List\u0026lt;Usuario\u0026gt; = usuarioService.listarTodos() @PostMapping @ResponseStatus(HttpStatus.CREATED) fun criar(@RequestBody request: CriarUsuarioRequest): Usuario = usuarioService.criar(request) } @Service class UsuarioService( private val repository: UsuarioRepository ) { fun listarTodos(): List\u0026lt;Usuario\u0026gt; = repository.findAll() fun criar(request: CriarUsuarioRequest): Usuario = repository.save(request.toEntity()) } Ktor oferece controle total sobre a configuração, sem magia de anotações. Spring Boot oferece convenções que reduzem o boilerplate para cenários comuns.\nPerformance Aspecto Ktor Spring Boot Startup time Rapido (1-3s) Mais lento (5-15s) Uso de memória Baixo (50-100MB) Maior (200-500MB) Throughput Alto Alto Latencia Baixa Baixa Coroutines Nativo Via WebFlux Ktor tem vantagem significativa em startup time e uso de memória, o que o torna ideal para microsservicos e ambientes serverless. Spring Boot compensa com um ecossistema mais rico e otimizações maduras para aplicações de longa duracao.\nEcossistema e integração Spring Boot possui o ecossistema mais abrangente do mundo Java/Kotlin. Spring Data oferece integração com dezenas de bancos de dados. Spring Security e o padrão para autenticação e autorizacao. Spring Cloud fornece ferramentas para microsservicos. E a integração com praticamente qualquer tecnologia já existe como starter.\nKtor possui um ecossistema menor mas crescente. Plugins oficiais cobrem as necessidades mais comuns como serialização, autenticação, CORS e WebSockets. Para funcionalidades adicionais, você pode integrar bibliotecas Java/Kotlin diretamente, embora com mais configuração manual.\nCoroutines e programação assíncrona Ktor foi construido sobre coroutines desde o inicio:\nrouting { get(\u0026#34;/dados\u0026#34;) { val resultado = coroutineScope { val usuarios = async { buscarUsuarios() } val pedidos = async { buscarPedidos() } DadosCombinados(usuarios.await(), pedidos.await()) } call.respond(resultado) } } Spring Boot suporta coroutines mas a integração não e tao natural. Com Spring WebFlux, você pode usar suspend functions nos controllers:\n@GetMapping(\u0026#34;/dados\u0026#34;) suspend fun buscarDados(): DadosCombinados = coroutineScope { val usuarios = async { buscarUsuarios() } val pedidos = async { buscarPedidos() } DadosCombinados(usuarios.await(), pedidos.await()) } A experiência com coroutines e mais fluida no Ktor, mas Spring Boot oferece suporte adequado para a maioria dos casos de uso.\nTestes Ktor oferece um test engine integrado:\n@Test fun testListarUsuarios() = testApplication { application { configurarRouting() } client.get(\u0026#34;/usuarios\u0026#34;).apply { assertEquals(HttpStatusCode.OK, status) } } Spring Boot oferece o Spring Test com MockMvc e WebTestClient:\n@SpringBootTest @AutoConfigureMockMvc class UsuarioControllerTest(@Autowired val mockMvc: MockMvc) { @Test fun testListarUsuarios() { mockMvc.get(\u0026#34;/usuarios\u0026#34;) .andExpect { status { isOk() } } } } Ambos oferecem ferramentas de teste adequadas. O test engine do Ktor e mais leve e rápido de executar, enquanto Spring Test oferece mais funcionalidades para testes de integração complexos.\nMercado de trabalho Spring Boot domina o mercado de backend Java/Kotlin no Brasil. A grande maioria das vagas de backend que mencionam Kotlin utilizam Spring Boot. Ktor esta crescendo, especialmente em startups e empresas que constroem microsservicos leves, mas ainda representa uma fracao menor do mercado.\nDominar Spring Boot abre mais portas imediatamente. Conhecer Ktor demonstra profundidade técnica e familiaridade com o ecossistema Kotlin nativo.\nCasos de uso recomendados Quando usar Ktor Ktor e ideal para microsservicos leves, aplicações serverless e lambdas, projetos que priorizam startup rápido e baixo consumo de memória, equipes que preferem controle total sobre a configuração e projetos Kotlin-first sem dependência do ecossistema Spring.\nQuando usar Spring Boot Spring Boot e ideal para aplicações enterprise com requisitos complexos, projetos que precisam de integração com múltiplas fontes de dados, equipes com experiência em Spring, aplicações monoliticas ou monolitos modulares e cenários onde o ecossistema Spring oferece solucoes prontas.\nVeredicto Em 2026, a escolha entre Ktor e Spring Boot depende do contexto. Para microsservicos leves e projetos Kotlin-first, Ktor oferece simplicidade, performance e uma experiência mais idiomatica. Para aplicações enterprise com requisitos complexos e equipes que precisam de um ecossistema abrangente, Spring Boot continua sendo a escolha mais segura. Fora do ecossistema JVM, Go com frameworks como Gin e Echo é uma alternativa popular para microsserviços de alta performance. Profissionais que dominam ambos os frameworks possuem o perfil mais completo para o mercado de backend Kotlin.\n","permalink":"https://kotlin.dev.br/comparacoes/ktor-vs-spring-boot/","summary":"\u003ch2 id=\"ktor-vs-spring-boot-em-2026-qual-framework-backend-escolher\"\u003eKtor vs Spring Boot em 2026: qual framework backend escolher?\u003c/h2\u003e\n\u003cp\u003eA escolha do framework backend é uma das decisoes mais impactantes em um projeto Kotlin. Ktor e Spring Boot são as duas opções dominantes, cada uma com filosofia e pontos fortes distintos. Ktor é o framework nativo de Kotlin criado pela JetBrains, enquanto Spring Boot é o gigante do ecossistema Java que oferece suporte completo a Kotlin. Este artigo compara ambos em profundidade.\u003c/p\u003e","title":"Ktor vs Spring Boot: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Vagas Kotlin remoto: como encontrar e conquistar oportunidades em 2026 O trabalho remoto transformou permanentemente o mercado de tecnologia. Para desenvolvedores Kotlin, essa mudanca abriu um universo de oportunidades que vai muito além das fronteiras geograficas. Trabalhar de casa para empresas brasileiras ou internacionais é uma realidade acessivel para profissionais qualificados. Neste guia completo, apresentamos tudo o que você precisa saber para encontrar e conquistar vagas remotas de Kotlin em 2026.\nPanorama das vagas remotas de Kotlin O mercado de vagas remotas para desenvolvedores Kotlin cresceu substancialmente nos últimos anos. Estima-se que mais de 60 por cento das vagas de desenvolvimento Kotlin publicadas no Brasil em 2026 oferecem alguma modalidade de trabalho remoto, seja totalmente remoto ou híbrido. No cenário internacional, esse percentual é ainda maior. Para quem está no começo da carreira, o checklist do eu.dev.br sobre como filtrar vaga remota júnior sem cair em falso júnior complementa bem essa busca antes de se candidatar em massa.\nAs vagas remotas de Kotlin se dividem em tres categorias principais. Vagas remotas nacionais são oferecidas por empresas brasileiras que adotaram o modelo distribuído. Vagas remotas internacionais são posicoes em empresas estrangeiras que contratam brasileiros. E vagas hibridas são aquelas que combinam dias no escritorio com dias remotos, geralmente em proporcao de dois a tres dias remotos por semana.\nFaixas salariais para vagas remotas Um dos maiores atrativos do trabalho remoto é a possibilidade de acessar faixas salariais mais elevadas independentemente de onde você mora:\nTipo de Vaga Junior Pleno Senior Remoto Brasil CLT R$ 3.500 - R$ 6.000 R$ 7.000 - R$ 13.000 R$ 13.000 - R$ 22.000 Remoto Brasil PJ R$ 5.000 - R$ 8.500 R$ 10.000 - R$ 17.000 R$ 17.000 - R$ 30.000 Remoto Internacional USD 2.000 - USD 3.500 USD 4.000 - USD 7.000 USD 7.000 - USD 13.000 Profissionais que moram em cidades com custo de vida mais baixo e trabalham remotamente para empresas de grandes centros ou do exterior conseguem um excelente custo-beneficio.\nOnde encontrar vagas remotas de Kotlin Plataformas brasileiras As principais plataformas para encontrar vagas remotas de Kotlin no Brasil incluem a Geek Hunter, que e especializada em tecnologia e possui um volume significativo de vagas Kotlin. A Programathor também e focada em desenvolvedores e oferece filtros por linguagem e modalidade. O LinkedIn continua sendo a maior plataforma de emprego e permite filtrar por vagas remotas com facilidade. A plataforma da Gupy concentra vagas de empresas de médio e grande porte que utilizam Kotlin.\nPlataformas internacionais Para vagas internacionais, o Toptal é uma das plataformas mais prestigiadas e oferece remuneracoes premium para profissionais aprovados em seu processo seletivo rigoroso. A Turing conecta desenvolvedores latino-americanos com empresas americanas. O site We Work Remotely e dedicado exclusivamente a vagas remotas e possui uma seção ativa de desenvolvimento. O Arc.dev e focado em desenvolvedores remotos e possui vagas de empresas de todo o mundo. E o Stack Overflow Jobs, embora tenha passado por mudancas, continua sendo uma referência para vagas tecnicas.\nComunidades e redes Grupos da comunidade Kotlin Brasil no Telegram e Discord frequentemente compartilham vagas. Participar ativamente dessas comunidades aumenta suas chances de encontrar oportunidades antes de serem publicadas em plataformas.\nHabilidades essenciais para trabalho remoto Alem das competencias tecnicas em Kotlin, o trabalho remoto exige habilidades específicas que impactam diretamente sua empregabilidade e permanencia nas posicoes.\nComunicação escrita No trabalho remoto, a maior parte da comunicação acontece por texto. A capacidade de escrever mensagens claras, documentar decisoes tecnicas e manter a equipe informada sobre seu progresso e fundamental. Profissionais que se comunicam bem por escrito se destacam em equipes distribuidas.\nAutodisciplina e gestao de tempo Sem a estrutura de um escritorio, você precisa gerenciar seu próprio tempo de forma eficiente. Estabelecer uma rotina de trabalho, definir limites claros entre trabalho e vida pessoal e manter a produtividade consistente são habilidades que empregadores remotos valorizam enormemente.\nIngles Para vagas internacionais, o ingles e requisito inegociavel. Mesmo para vagas em empresas brasileiras, o ingles técnico e frequentemente necessário para participar de reunioes com equipes globais, ler documentação e contribuir para projetos multilinguais.\nFamiliaridade com ferramentas de colaboracao Dominio de ferramentas como Slack, Jira, Confluence, GitHub e plataformas de videoconferencia e esperado. Saber utilizar essas ferramentas de forma eficiente e parte integrante do perfil de um profissional remoto.\nDicas para conquistar vagas remotas Prepare seu ambiente de trabalho Antes de se candidatar, certifique-se de ter um espaco de trabalho adequado, conexao de internet estavel e equipamentos funcionais. Muitas empresas perguntam sobre seu setup durante o processo seletivo.\nAdapte seu curriculo Destaque experiencias anteriores de trabalho remoto, projetos colaborativos distribuidos e habilidades de comunicação assíncrona. Se você ainda não tem experiência remota, mencione projetos open source ou trabalhos freelance realizados remotamente.\nDomine entrevistas por video Pratique entrevistas tecnicas por videoconferencia. Familiarize-se com plataformas de coding interview como CoderPad e HackerRank. Teste seu audio e video antes de cada entrevista e escolha um ambiente silencioso e bem iluminado.\nConstrua presenca online Um perfil no GitHub com projetos ativos, um LinkedIn bem elaborado e contribuicoes visiveis para a comunidade Kotlin aumentam significativamente suas chances de ser encontrado por recrutadores.\nAspectos legais e tributarios Trabalhar remotamente para empresas internacionais envolve questões legais e tributarias que devem ser consideradas. A maioria dos brasileiros que trabalha para empresas estrangeiras utiliza o regime PJ, geralmente com CNPJ no Simples Nacional. E fundamental manter um controle rigoroso da documentação fiscal e considerar a assessoria de um contador especializado em operações internacionais.\nPara recebimentos em moeda estrangeira, serviços como Wise, Payoneer e Husky oferecem taxas competitivas para transferencias internacionais. Compare as opções e escolha a que melhor se adequa ao seu volume de transacoes.\nConclusão As vagas remotas de Kotlin representam uma das melhores oportunidades no mercado de tecnologia em 2026. Com salários que podem variar de R$ 3.500 até mais de R$ 60.000 mensais no mercado internacional, o trabalho remoto democratizou o acesso a oportunidades de alta remuneracao. Investir em habilidades tecnicas, comunicação, ingles e presenca online são os passos fundamentais para conquistar as melhores posicoes remotas disponiveis. Outras linguagens com forte demanda remota incluem Go e Python — vale a pena acompanhar o mercado dessas tecnologias também.\n","permalink":"https://kotlin.dev.br/carreira/vagas-kotlin-remoto/","summary":"\u003ch2 id=\"vagas-kotlin-remoto-como-encontrar-e-conquistar-oportunidades-em-2026\"\u003eVagas Kotlin remoto: como encontrar e conquistar oportunidades em 2026\u003c/h2\u003e\n\u003cp\u003eO trabalho remoto transformou permanentemente o mercado de tecnologia. Para desenvolvedores Kotlin, essa mudanca abriu um universo de oportunidades que vai muito além das fronteiras geograficas. Trabalhar de casa para empresas brasileiras ou internacionais é uma realidade acessivel para profissionais qualificados. Neste guia completo, apresentamos tudo o que você precisa saber para encontrar e conquistar vagas remotas de Kotlin em 2026.\u003c/p\u003e","title":"Vagas Kotlin Remoto: Guia Completo para Trabalhar de Casa em 2026 | Kotlin Brasil"},{"content":"Jetpack Compose vs XML em 2026: o futuro da UI Android A construcao de interfaces no Android passou por uma transformacao fundamental com a chegada do Jetpack Compose. A abordagem declarativa em Kotlin substituiu gradualmente o modelo imperativo baseado em XML que dominou o Android desde seu lancamento. Este artigo compara as duas abordagens em detalhes para ajudar você a tomar a melhor decisao em 2026.\nVisao geral Caracteristica Jetpack Compose XML Paradigma Declarativo Imperativo Linguagem Kotlin XML + Java/Kotlin Lancamento 2021 2008 (com o Android) Estado Recomendado pelo Google Legado suportado Preview Em tempo real no IDE Layout Editor visual Curva de aprendizado Moderada Familiar mas verbosa reutilização Alta (composables) Moderada (includes/custom views) Paradigma declarativo versus imperativo A diferenca fundamental esta na forma como cada abordagem descreve a interface.\nJetpack Compose descreve o que a interface deve mostrar:\n@Composable fun ListaUsuarios(usuarios: List\u0026lt;Usuario\u0026gt;) { LazyColumn { items(usuarios) { usuario -\u0026gt; Card( modifier = Modifier .fillMaxWidth() .padding(8.dp) ) { Column(modifier = Modifier.padding(16.dp)) { Text( text = usuario.nome, style = MaterialTheme.typography.headlineSmall ) Text( text = usuario.email, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant ) } } } } } XML define a estrutura e o código Java/Kotlin manipula o estado:\n\u0026lt;!-- lista_usuarios.xml --\u0026gt; \u0026lt;androidx.recyclerview.widget.RecyclerView android:id=\u0026#34;@+id/recyclerView\u0026#34; android:layout_width=\u0026#34;match_parent\u0026#34; android:layout_height=\u0026#34;match_parent\u0026#34; /\u0026gt; \u0026lt;!-- item_usuario.xml --\u0026gt; \u0026lt;com.google.android.material.card.MaterialCardView android:layout_width=\u0026#34;match_parent\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:layout_margin=\u0026#34;8dp\u0026#34;\u0026gt; \u0026lt;LinearLayout android:layout_width=\u0026#34;match_parent\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:orientation=\u0026#34;vertical\u0026#34; android:padding=\u0026#34;16dp\u0026#34;\u0026gt; \u0026lt;TextView android:id=\u0026#34;@+id/nomeText\u0026#34; android:layout_width=\u0026#34;wrap_content\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:textAppearance=\u0026#34;?attr/textAppearanceHeadlineSmall\u0026#34; /\u0026gt; \u0026lt;TextView android:id=\u0026#34;@+id/emailText\u0026#34; android:layout_width=\u0026#34;wrap_content\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:textAppearance=\u0026#34;?attr/textAppearanceBodyMedium\u0026#34; /\u0026gt; \u0026lt;/LinearLayout\u0026gt; \u0026lt;/com.google.android.material.card.MaterialCardView\u0026gt; Alem do XML, o sistema tradicional exige um Adapter, ViewHolder e lógica de binding, resultando em significativamente mais código para o mesmo resultado.\nGerenciamento de estado Compose oferece gerenciamento de estado integrado e reativo:\n@Composable fun Contador() { var contagem by remember { mutableIntStateOf(0) } Column(horizontalAlignment = Alignment.CenterHorizontally) { Text(\u0026#34;Contagem: $contagem\u0026#34;, style = MaterialTheme.typography.headlineMedium) Button(onClick = { contagem++ }) { Text(\u0026#34;Incrementar\u0026#34;) } } } Em XML, o gerenciamento de estado requer mais boilerplate:\nclass ContadorFragment : Fragment() { private var contagem = 0 private lateinit var textoContagem: TextView override fun onViewCreated(view: View, savedInstanceState: Bundle?) { textoContagem = view.findViewById(R.id.textoContagem) val botao = view.findViewById\u0026lt;Button\u0026gt;(R.id.botaoIncrementar) atualizarTexto() botao.setOnClickListener { contagem++ atualizarTexto() } } private fun atualizarTexto() { textoContagem.text = \u0026#34;Contagem: $contagem\u0026#34; } } Compose elimina a necessidade de sincronizar manualmente o estado com a UI, reduzindo bugs e simplificando o código.\nPerformance Aspecto Jetpack Compose XML Renderizacao inicial Similar Similar atualizações de UI Inteligente (recomposicao) Manual (invalidate) Memória Otimizado View hierarchy overhead Listas longas LazyColumn eficiente RecyclerView eficiente Animacoes API moderna e fluida Mais verbose mas funcional Na prática, a performance de ambas as abordagens e adequada para a grande maioria das aplicações. Compose possui recomposicao inteligente que atualiza apenas os composables afetados por mudancas de estado, o que pode ser mais eficiente que o modelo de invalidacao do sistema de views.\nProdutividade e manutenção Compose oferece vantagens significativas em produtividade. A eliminacao de arquivos XML separados, adapters e view holders reduz a quantidade de código e arquivos no projeto. A preview em tempo real no Android Studio permite iterar rapidamente no design. E a composição de componentes facilita a reutilização de UI.\nXML possui a vantagem de ser uma tecnologia madura com vasta documentação, exemplos e solucoes para problemas comuns. Profissionais com experiência em XML podem ser produtivos imediatamente sem aprender novos conceitos.\nTestes Compose oferece uma API de testes integrada e intuitiva:\n@Test fun contadorDeveIncrementar() { composeTestRule.setContent { Contador() } composeTestRule.onNodeWithText(\u0026#34;Contagem: 0\u0026#34;).assertIsDisplayed() composeTestRule.onNodeWithText(\u0026#34;Incrementar\u0026#34;).performClick() composeTestRule.onNodeWithText(\u0026#34;Contagem: 1\u0026#34;).assertIsDisplayed() } Testes de UI com XML utilizam Espresso, que e funcional mas mais verboso e com setup mais complexo.\nMigração e coexistencia Compose e XML podem coexistir no mesmo projeto. E possível usar composables dentro de layouts XML com ComposeView e usar views XML dentro de composables com AndroidView. Essa interoperabilidade permite uma migração gradual sem necessidade de reescrever toda a aplicação de uma vez.\nCasos de uso recomendados Quando usar Jetpack Compose Compose e recomendado para todos os novos projetos Android, projetos que buscam maxima produtividade, interfaces dinamicas com muito estado, e equipes que desejam adotar as melhores práticas atuais do Android.\nQuando manter XML XML pode ser mantido em projetos legados grandes onde a migração total e inviavel, em equipes sem experiência com Compose e sem tempo para treinamento, e em componentes muito específicos que dependem de custom views complexas.\nVeredicto Em 2026, Jetpack Compose e a escolha definitiva para desenvolvimento de UI Android. O Google o posiciona como o futuro da plataforma, com investimento continuo em novas funcionalidades e melhorias de performance. XML permanece suportado e funcional para projetos existentes, mas não e recomendado para novos desenvolvimentos. Profissionais que ainda não dominam Compose devem priorizar esse aprendizado, pois o mercado cada vez mais exige essa competencia.\n","permalink":"https://kotlin.dev.br/comparacoes/jetpack-compose-vs-xml/","summary":"\u003ch2 id=\"jetpack-compose-vs-xml-em-2026-o-futuro-da-ui-android\"\u003eJetpack Compose vs XML em 2026: o futuro da UI Android\u003c/h2\u003e\n\u003cp\u003eA construcao de interfaces no Android passou por uma transformacao fundamental com a chegada do Jetpack Compose. A abordagem declarativa em Kotlin substituiu gradualmente o modelo imperativo baseado em XML que dominou o Android desde seu lancamento. Este artigo compara as duas abordagens em detalhes para ajudar você a tomar a melhor decisao em 2026.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracteristica\u003c/th\u003e\n          \u003cth\u003eJetpack Compose\u003c/th\u003e\n          \u003cth\u003eXML\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eParadigma\u003c/td\u003e\n          \u003ctd\u003eDeclarativo\u003c/td\u003e\n          \u003ctd\u003eImperativo\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eLinguagem\u003c/td\u003e\n          \u003ctd\u003eKotlin\u003c/td\u003e\n          \u003ctd\u003eXML + Java/Kotlin\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eLancamento\u003c/td\u003e\n          \u003ctd\u003e2021\u003c/td\u003e\n          \u003ctd\u003e2008 (com o Android)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eEstado\u003c/td\u003e\n          \u003ctd\u003eRecomendado pelo Google\u003c/td\u003e\n          \u003ctd\u003eLegado suportado\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePreview\u003c/td\u003e\n          \u003ctd\u003eEm tempo real no IDE\u003c/td\u003e\n          \u003ctd\u003eLayout Editor visual\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCurva de aprendizado\u003c/td\u003e\n          \u003ctd\u003eModerada\u003c/td\u003e\n          \u003ctd\u003eFamiliar mas verbosa\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ereutilização\u003c/td\u003e\n          \u003ctd\u003eAlta (composables)\u003c/td\u003e\n          \u003ctd\u003eModerada (includes/custom views)\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"paradigma-declarativo-versus-imperativo\"\u003eParadigma declarativo versus imperativo\u003c/h2\u003e\n\u003cp\u003eA diferenca fundamental esta na forma como cada abordagem descreve a interface.\u003c/p\u003e","title":"Jetpack Compose vs XML: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"O ecossistema Kotlin amadureceu significativamente e hoje conta com bibliotecas de alta qualidade para praticamente qualquer necessidade. Seja para backend, Android, multiplatform ou testes, existe uma solução em Kotlin puro ou com suporte excelente a linguagem. Neste artigo, reunimos as bibliotecas mais relevantes em 2026 com exemplos práticos de cada uma.\nBackend e APIs Ktor Ktor é o framework web assíncrono da JetBrains, construido 100% em Kotlin com coroutines. Ele se destaca pela leveza, modularidade e suporte nativo a Kotlin Multiplatform, funcionando tanto como servidor quanto como cliente HTTP.\nimport io.ktor.server.application.* import io.ktor.server.engine.* import io.ktor.server.netty.* import io.ktor.server.response.* import io.ktor.server.routing.* import io.ktor.serialization.kotlinx.json.* import io.ktor.server.plugins.contentnegotiation.* @Serializable data class Usuario(val id: Int, val nome: String) fun main() { embeddedServer(Netty, port = 8080) { install(ContentNegotiation) { json() } routing { get(\u0026#34;/usuarios\u0026#34;) { val usuarios = listOf( Usuario(1, \u0026#34;Ana\u0026#34;), Usuario(2, \u0026#34;Carlos\u0026#34;) ) call.respond(usuarios) } } }.start(wait = true) } Em 2026, Ktor 3.x trouxe melhorias significativas em performance e suporte a HTTP/3. O ecossistema de plugins cresceu e a integração com Kotlin Multiplatform permite compartilhar a lógica de cliente HTTP entre Android, iOS e backend.\nExposed Exposed e o framework de acesso a banco de dados da JetBrains que oferece duas APIs: DSL tipada e DAO leve. Ambas aproveitam o sistema de tipos de Kotlin para queries seguras em tempo de compilação.\nimport org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.transaction object Usuarios : Table() { val id = integer(\u0026#34;id\u0026#34;).autoIncrement() val nome = varchar(\u0026#34;nome\u0026#34;, 100) val email = varchar(\u0026#34;email\u0026#34;, 200) val ativo = bool(\u0026#34;ativo\u0026#34;).default(true) override val primaryKey = PrimaryKey(id) } fun main() { Database.connect(\u0026#34;jdbc:h2:mem:test\u0026#34;, driver = \u0026#34;org.h2.Driver\u0026#34;) transaction { SchemaUtils.create(Usuarios) Usuarios.insert { it[nome] = \u0026#34;Ana Silva\u0026#34; it[email] = \u0026#34;ana@email.com\u0026#34; } val ativos = Usuarios .select(Usuarios.nome, Usuarios.email) .where { Usuarios.ativo eq true } .map { \u0026#34;${it[Usuarios.nome]} - ${it[Usuarios.email]}\u0026#34; } ativos.forEach(::println) } } kotlinx.serialization A biblioteca oficial de serialização da JetBrains suporta JSON, Protobuf, CBOR e outros formatos. Diferente de solucoes baseadas em reflexao como Gson, ela usa geracao de código em tempo de compilação, resultando em performance superior.\nimport kotlinx.serialization.* import kotlinx.serialization.json.* @Serializable data class Configuração( val nome: String, @SerialName(\u0026#34;max_conexoes\u0026#34;) val maxConexoes: Int = 10, val tags: List\u0026lt;String\u0026gt; = emptyList() ) fun main() { val json = Json { prettyPrint = true ignoreUnknownKeys = true } val config = Configuração(\u0026#34;Producao\u0026#34;, 50, listOf(\u0026#34;api\u0026#34;, \u0026#34;v2\u0026#34;)) val texto = json.encodeToString(config) println(texto) val restaurado = json.decodeFromString\u0026lt;Configuração\u0026gt;(texto) println(restaurado) } Android Jetpack Compose Compose e o toolkit declarativo de UI para Android (e agora multiplataforma). Em 2026, ele e a abordagem recomendada pelo Google para construir interfaces, com Compose Material 3 totalmente estavel e adoção massiva pela comunidade.\n@Composable fun CartaoProduto(produto: Produto, onComprar: () -\u0026gt; Unit) { Card( modifier = Modifier .fillMaxWidth() .padding(8.dp), elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) ) { Column(modifier = Modifier.padding(16.dp)) { Text( text = produto.nome, style = MaterialTheme.typography.titleMedium ) Text( text = \u0026#34;R$ ${\u0026#34;%.2f\u0026#34;.format(produto.preco)}\u0026#34;, style = MaterialTheme.typography.bodyLarge ) Spacer(modifier = Modifier.height(8.dp)) Button(onClick = onComprar) { Text(\u0026#34;Comprar\u0026#34;) } } } } Coil Coil (Coroutine Image Loader) e a biblioteca padrão para carregamento de imagens em Android com Kotlin. Construida com coroutines e suporte nativo a Compose, ela substituiu Glide e Picasso em muitos projetos.\n@Composable fun AvatarUsuario(urlImagem: String) { AsyncImage( model = ImageRequest.Builder(LocalContext.current) .data(urlImagem) .crossfade(true) .build(), contentDescription = \u0026#34;Avatar do usuario\u0026#34;, modifier = Modifier .size(64.dp) .clip(CircleShape), contentScale = ContentScale.Crop ) } Kotlin Multiplatform Koin Koin e um framework de injeção de dependência pragmatico, sem geracao de código nem anotações. Ele funciona em todas as plataformas Kotlin e se integra nativamente com ViewModel e Compose.\nval moduloApp = module { single\u0026lt;UsuarioRepositorio\u0026gt; { UsuarioRepositorioImpl(get()) } single { BancoDeDados.criar() } viewModel { ListaUsuariosViewModel(get()) } } // Inicialização startKoin { modules(moduloApp) } // Uso em Compose @Composable fun TelaUsuarios( viewModel: ListaUsuariosViewModel = koinViewModel() ) { val usuarios by viewModel.usuarios.collectAsStateWithLifecycle() // ... } SQLDelight SQLDelight gera código Kotlin tipado a partir de queries SQL. Ele suporta Android, iOS, JVM e JavaScript, tornando-o ideal para projetos Kotlin Multiplatform que precisam de banco de dados local.\n-- src/commonMain/sqldelight/com/exemplo/Tarefa.sq CREATE TABLE Tarefa ( id INTEGER PRIMARY KEY AUTOINCREMENT, titulo TEXT NOT NULL, concluida INTEGER NOT NULL DEFAULT 0 ); selectTodas: SELECT * FROM Tarefa ORDER BY id DESC; inserir: INSERT INTO Tarefa(titulo, concluida) VALUES (?, ?); marcarConcluida: UPDATE Tarefa SET concluida = 1 WHERE id = ?; // Código gerado permite uso tipado val tarefas: Flow\u0026lt;List\u0026lt;Tarefa\u0026gt;\u0026gt; = queries.selectTodas().asFlow().mapToList(Dispatchers.IO) fun adicionar(titulo: String) { queries.inserir(titulo, 0) } Multiplatform Settings Biblioteca simples para armazenamento chave-valor em Kotlin Multiplatform, usando SharedPreferences no Android, NSUserDefaults no iOS e localStorage na web.\n// Código compartilhado class PreferenciasUsuario(private val settings: Settings) { var tema: String get() = settings.getString(\u0026#34;tema\u0026#34;, \u0026#34;claro\u0026#34;) set(value) { settings.putString(\u0026#34;tema\u0026#34;, value) } var notificacoesAtivas: Boolean get() = settings.getBoolean(\u0026#34;notificacoes\u0026#34;, true) set(value) { settings.putBoolean(\u0026#34;notificacoes\u0026#34;, value) } } Testes Kotest Kotest e o framework de testes mais completo para Kotlin, com múltiplos estilos de escrita (BDD, spec, funcional), assertions ricas e suporte a property-based testing.\nclass CalculadoraTest : FunSpec({ test(\u0026#34;soma de dois numeros positivos\u0026#34;) { val calc = Calculadora() calc.somar(2, 3) shouldBe 5 } test(\u0026#34;divisao por zero lanca excecao\u0026#34;) { val calc = Calculadora() shouldThrow\u0026lt;ArithmeticException\u0026gt; { calc.dividir(10, 0) } } context(\u0026#34;validação de email\u0026#34;) { test(\u0026#34;aceita formato valido\u0026#34;) { \u0026#34;usuario@dominio.com\u0026#34;.shouldMatch(Regex(\u0026#34;.+@.+\\\\..+\u0026#34;)) } test(\u0026#34;rejeita formato invalido\u0026#34;) { \u0026#34;usuario-sem-arroba\u0026#34;.shouldNotMatch(Regex(\u0026#34;.+@.+\\\\..+\u0026#34;)) } } }) MockK MockK e a biblioteca de mocking nativa para Kotlin, com suporte completo a coroutines, extension functions e classes seladas.\nclass UsuarioServiceTest { private val repositorio = mockk\u0026lt;UsuarioRepositorio\u0026gt;() private val service = UsuarioService(repositorio) @Test fun `buscar usuario existente retorna dados`() = runTest { val esperado = Usuario(1, \u0026#34;Ana\u0026#34;, \u0026#34;ana@email.com\u0026#34;) coEvery { repositorio.buscarPorId(1) } returns esperado val resultado = service.buscar(1) resultado shouldBe esperado coVerify(exactly = 1) { repositorio.buscarPorId(1) } } } Concorrência e Fluxos Reativos kotlinx.coroutines A base de toda a programação assíncrona em Kotlin. Em 2026, a biblioteca esta extremamente madura com Flow, StateFlow, SharedFlow e integração perfeita com todas as plataformas.\nfun buscaComTimeout() = flow { val resultado = withTimeout(5000) { repositorio.buscarDados() } emit(resultado) }.catch { e -\u0026gt; emit(ResultadoPadrao.vazio()) }.flowOn(Dispatchers.IO) Ferramentas de Build Gradle Kotlin DSL O Gradle com Kotlin DSL e o padrão para projetos Kotlin. Com version catalogs e convention plugins, a configuração de build ficou mais organizada e tipada.\n// build.gradle.kts plugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.ktor) alias(libs.plugins.serialization) } dependencies { implementation(libs.ktor.server.core) implementation(libs.ktor.server.netty) testImplementation(libs.kotest.runner) } Conclusão O ecossistema Kotlin em 2026 oferece bibliotecas maduras para todos os cenários de desenvolvimento. A tendencia clara e a convergencia para Kotlin Multiplatform, com bibliotecas como Ktor, SQLDelight e Koin funcionando em todas as plataformas. Para novos projetos, priorize bibliotecas com suporte a coroutines, tipagem forte e compatibilidade multiplataforma. Essas escolhas garantem um código moderno, eficiente e preparado para o futuro. Cada linguagem tem seu próprio ecossistema de bibliotecas excelentes — confira também os ecossistemas de Go e Python.\n","permalink":"https://kotlin.dev.br/blog/melhores-bibliotecas-kotlin/","summary":"\u003cp\u003eO ecossistema Kotlin amadureceu significativamente e hoje conta com bibliotecas de alta qualidade para praticamente qualquer necessidade. Seja para backend, Android, multiplatform ou testes, existe uma solução em Kotlin puro ou com suporte excelente a linguagem. Neste artigo, reunimos as bibliotecas mais relevantes em 2026 com exemplos práticos de cada uma.\u003c/p\u003e\n\u003ch2 id=\"backend-e-apis\"\u003eBackend e APIs\u003c/h2\u003e\n\u003ch3 id=\"ktor\"\u003eKtor\u003c/h3\u003e\n\u003cp\u003eKtor é o framework web assíncrono da JetBrains, construido 100% em Kotlin com coroutines. Ele se destaca pela leveza, modularidade e suporte nativo a Kotlin Multiplatform, funcionando tanto como servidor quanto como cliente HTTP.\u003c/p\u003e","title":"Melhores Bibliotecas Kotlin em 2026 | Kotlin Brasil"},{"content":"Quanto ganha um desenvolvedor backend Kotlin em 2026? O Kotlin no backend deixou de ser uma tendencia para se tornar uma realidade consolidada no mercado brasileiro. Empresas de todos os portes estao adotando a linguagem para construir APIs, microsservicos e sistemas distribuidos, impulsionadas pela produtividade superior e pela interoperabilidade com o ecossistema Java. Se você trabalha ou pretende trabalhar com backend em Kotlin, este artigo apresenta as faixas salariais detalhadas para 2026.\nFaixa salarial por nível de experiência O mercado diferencia claramente os salários de acordo com o nível de experiência é o dominio técnico do profissional:\nNível CLT (mensal) PJ (mensal) Remoto Internacional Junior (0-2 anos) R$ 3.800 - R$ 6.500 R$ 5.500 - R$ 9.000 USD 2.500 - USD 4.000 Pleno (2-5 anos) R$ 7.500 - R$ 14.000 R$ 10.500 - R$ 18.000 USD 4.000 - USD 7.000 Senior (5+ anos) R$ 14.000 - R$ 24.000 R$ 18.000 - R$ 32.000 USD 7.000 - USD 13.000 E importante notar que desenvolvedores backend Kotlin geralmente recebem salários ligeiramente superiores aos desenvolvedores Android no mesmo nível. Isso se deve a complexidade adicional de sistemas distribuidos é a menor oferta de profissionais especializados em backend com Kotlin.\nFatores que influenciam o salário Framework utilizado O framework que você domina impacta diretamente sua remuneracao. Profissionais com experiência em Spring Boot com Kotlin representam a maior fatia do mercado e recebem salários alinhados com as faixas apresentadas. Ja profissionais que dominam Ktor, o framework nativo de Kotlin criado pela JetBrains, podem receber um premium de 10 a 15 por cento, pois a demanda por esse conhecimento específico esta crescendo mais rápido que a oferta.\nConhecimento em sistemas distribuidos Experiência com arquitetura de microsservicos, mensageria com Kafka ou RabbitMQ, cache distribuído com Redis e bancos de dados como PostgreSQL e MongoDB eleva significativamente o valor do profissional no mercado.\nCloud e DevOps Profissionais que combinam desenvolvimento backend com conhecimentos em AWS, GCP ou Azure, containers Docker e orquestracao com Kubernetes recebem propostas diferenciadas. Essa combinacao de habilidades e particularmente valorizada em empresas que adotam cultura DevOps.\nVariacao por região Grande São Paulo O polo financeiro e tecnologico do Brasil oferece os melhores salários. Fintechs como Nubank, PicPay e C6 Bank, além de empresas como Mercado Livre e Magazine Luiza, lideram as contratacoes de backend Kotlin com remuneracoes acima da media nacional.\nSul e Sudeste Belo Horizonte, Curitiba, Porto Alegre e Florianopolis formam o segundo tier de salários, com valores tipicamente 10 a 20 por cento menores que São Paulo. No entanto, o custo de vida mais baixo nessas cidades pode resultar em um poder de compra equivalente ou superior.\nNordeste e Norte Recife e Fortaleza lideram o mercado de tecnologia no Nordeste, com salários que crescem aceleradamento. A diferenca para São Paulo ainda e de 20 a 30 por cento, mas a tendencia e de convergencia conforme o trabalho remoto se consolida.\nHabilidades mais valorizadas Kotlin idiomatico Dominar Kotlin de forma idiomatica vai além de simplesmente escrever código que compila. Significa utilizar extension functions, sealed classes, coroutines e flows de maneira elegante e eficiente. Profissionais que escrevem Kotlin idiomatico demonstram maturidade técnica e são mais valorizados.\nCoroutines e programação assíncrona O dominio de coroutines e fundamental para desenvolvimento backend eficiente. Entender structured concurrency, channels, flows é o modelo de cancelamento e essencial para construir aplicações backend performaticas e resilientes.\nTestes e qualidade Experiência com testes unitarios usando JUnit 5, MockK e Kotest, testes de integração com Testcontainers e testes de contrato com Pact são habilidades que diferenciam profissionais e justificam salários acima da media.\nObservabilidade Conhecimento em ferramentas de monitoramento como Prometheus, Grafana, Datadog e plataformas de logging como ELK Stack ou Splunk e cada vez mais exigido para posicoes de backend, especialmente em niveis pleno e senior.\nAnálise do mercado O backend Kotlin esta em plena expansao no Brasil. A migração de aplicações Java para Kotlin é um movimento que ganha forca em empresas de todos os tamanhos, desde startups até grandes corporacoes bancarias e de varejo. Essa transicao gera demanda tanto por novos profissionais quanto por consultores que auxiliam no processo de migração.\nO crescimento do ecossistema de server-side Kotlin, com frameworks maduros e suporte robusto da JetBrains, solidifica a posicao da linguagem como uma alternativa superior ao Java para novos projetos. Empresas que já utilizam a JVM em producao encontram em Kotlin uma evolução natural que traz ganhos de produtividade sem sacrificar a compatibilidade com o ecossistema existente.\nDicas para maximizar seu salário Invista em aprender Ktor além do Spring Boot. O conhecimento de ambos os frameworks amplia significativamente suas opções no mercado. Domine ao menos um provedor de cloud em profundidade, preferencialmente AWS, que lidera o mercado brasileiro. Contribua para projetos open source de backend em Kotlin para construir sua reputacao. Desenvolva habilidades em arquitetura de sistemas, pois é o que diferencia um senior de um pleno no backend. E considere seriamente investir em ingles fluente para acessar o mercado internacional, onde os salários são multiplicados.\nConclusão O desenvolvedor backend Kotlin no Brasil em 2026 desfruta de um mercado aquecido e salários competitivos que variam de R$ 3.800 para juniors até R$ 32.000 ou mais para seniors no regime PJ. O mercado internacional eleva esse teto para patamares ainda mais atrativos. A especializacao em frameworks como Ktor e Spring Boot, combinada com conhecimentos em sistemas distribuidos e cloud, é o caminho mais eficaz para acessar as melhores oportunidades. Para comparar com outras linguagens backend, veja os salários de desenvolvedores Go e as faixas salariais de Rust no Brasil.\n","permalink":"https://kotlin.dev.br/carreira/salario-dev-backend-kotlin/","summary":"\u003ch2 id=\"quanto-ganha-um-desenvolvedor-backend-kotlin-em-2026\"\u003eQuanto ganha um desenvolvedor backend Kotlin em 2026?\u003c/h2\u003e\n\u003cp\u003eO Kotlin no backend deixou de ser uma tendencia para se tornar uma realidade consolidada no mercado brasileiro. Empresas de todos os portes estao adotando a linguagem para construir APIs, microsservicos e sistemas distribuidos, impulsionadas pela produtividade superior e pela interoperabilidade com o ecossistema Java. Se você trabalha ou pretende trabalhar com backend em Kotlin, este artigo apresenta as faixas salariais detalhadas para 2026.\u003c/p\u003e","title":"Salário de Desenvolvedor Backend Kotlin: Quanto Ganha em 2026 | Kotlin Brasil"},{"content":"Kotlin vs Clojure em 2026: duas filosofias na JVM Kotlin e Clojure representam abordagens radicalmente diferentes para desenvolvimento na JVM. Kotlin é uma linguagem multiparadigma com foco em pragmatismo, enquanto Clojure é um dialeto de Lisp com foco em programação funcional e imutabilidade. Este artigo compara as duas linguagens para ajudar você a entender onde cada uma se destaca.\nVisao geral Caracteristica Kotlin Clojure Paradigma OO + Funcional Funcional (Lisp) Tipagem Estática Dinamica Sintaxe Baseada em C/Java Baseada em Lisp (S-expressions) Criador JetBrains Rich Hickey Ano 2016 2007 Imutabilidade Opcional (val/var) Padrao REPL Sim Sim (central ao workflow) Android Suporte oficial Limitado Sintaxe e paradigma A diferenca mais visivel entre as linguagens é a sintaxe. Kotlin utiliza uma sintaxe familiar para desenvolvedores de Java e C:\ndata class Pedido(val id: Int, val itens: List\u0026lt;Item\u0026gt;, val total: Double) fun calcularDesconto(pedidos: List\u0026lt;Pedido\u0026gt;): Double { return pedidos .filter { it.total \u0026gt; 100.0 } .sumOf { it.total * 0.1 } } fun main() { val pedidos = listOf( Pedido(1, emptyList(), 150.0), Pedido(2, emptyList(), 80.0), Pedido(3, emptyList(), 200.0) ) println(\u0026#34;Desconto total: ${calcularDesconto(pedidos)}\u0026#34;) } Clojure utiliza S-expressions herdadas de Lisp:\n(defrecord Pedido [id itens total]) (defn calcular-desconto [pedidos] (-\u0026gt;\u0026gt; pedidos (filter #(\u0026gt; (:total %) 100.0)) (map #(* (:total %) 0.1)) (reduce +))) (defn -main [] (let [pedidos [(-\u0026gt;Pedido 1 [] 150.0) (-\u0026gt;Pedido 2 [] 80.0) (-\u0026gt;Pedido 3 [] 200.0)]] (println \u0026#34;Desconto total:\u0026#34; (calcular-desconto pedidos)))) A sintaxe de Clojure e minimalista e uniforme, o qué fácilita a metaprogramação com macros, mas pode ser intimidante para quem não esta familiarizado com Lisp. A sintaxe de Kotlin e imediatamente acessivel para a maioria dos desenvolvedores.\nImutabilidade e estado Clojure foi projetada em torno da imutabilidade. Todas as estruturas de dados são imutáveis por padrão, e o estado mutavel e gerenciado por construcoes controladas como atoms, refs e agents:\n;; Estruturas imutáveis por padrao (def dados {:nome \u0026#34;Maria\u0026#34; :idade 30}) (def atualizado (assoc dados :idade 31)) ;; cria nova estrutura ;; Estado gerenciado com atom (def contador (atom 0)) (swap! contador inc) ;; incremento atomico Kotlin oferece imutabilidade opcional com val e collections imutáveis:\nval dados = mapOf(\u0026#34;nome\u0026#34; to \u0026#34;Maria\u0026#34;, \u0026#34;idade\u0026#34; to 30) val atualizado = dados + (\u0026#34;idade\u0026#34; to 31) // Estado mutavel quando necessario var contador = 0 contador++ A abordagem de Clojure e mais rigorosa e adequada para sistemas altamente concorrentes. A de Kotlin e mais flexivel e permite escolher o nível de imutabilidade conforme a necessidade.\nConcorrência Clojure possui um modelo de concorrência sofisticado baseado em STM (Software Transactional Memory), atoms e core.async:\n(require \u0026#39;[clojure.core.async :as async]) (let [ch (async/chan)] (async/go (async/\u0026gt;! ch \u0026#34;dados processados\u0026#34;)) (async/go (println (async/\u0026lt;! ch)))) Kotlin oferece coroutines como mecanismo principal de concorrência:\nimport kotlinx.coroutines.* fun main() = runBlocking { val resultado = async { processarDados() } println(resultado.await()) } Ambas as abordagens são superiores ao modelo de threads tradicional do Java. Coroutines de Kotlin são mais amplamente adotadas e possuem melhor suporte de tooling. O modelo de Clojure e mais expressivo para certos padrões de concorrência complexos.\nPerformance Aspecto Kotlin Clojure Startup Rapido Lento (carrega runtime) Throughput Alto Bom Uso de memória Eficiente Maior (estruturas persistentes) Compilação Rapida AOT ou JIT Interop Java Direta Possivel mas verbosa Kotlin tem vantagem em startup time e uso de memória. Clojure carrega um runtime maior e suas estruturas de dados persistentes imutáveis usam mais memória, embora sejam eficientes em cenários de concorrência pesada.\nEcossistema O ecossistema de Kotlin inclui Spring Boot, Ktor, Jetpack Compose, Kotlin Multiplatform e milhares de bibliotecas Java compattiveis. O ecossistema de Clojure inclui Ring e Compojure para web, Datomic como banco de dados imutavel, Reagent e Re-frame para frontend com ClojureScript, e Leiningen e deps.edn como ferramentas de build.\nO ecossistema de Kotlin e significativamente maior e mais diversificado. O de Clojure e menor mas coeso, com bibliotecas que seguem a filosofia da linguagem de forma consistente.\nMercado de trabalho O mercado de trabalho para Kotlin no Brasil e muito maior que para Clojure. Kotlin possui milhares de vagas mensais em Android, backend e multiplataforma. Clojure tem um nicho menor mas fiel, com vagas concentradas em empresas como Nubank (um dos maiores usuários de Clojure do mundo), e em startups que valorizam programação funcional.\nOs salários de Clojure tendem a ser altos devido a escassez de profissionais, mas o volume de oportunidades e limitado.\nCurva de aprendizado Kotlin possui uma curva de aprendizado moderada, especialmente para quem vem de Java. A sintaxe familiar e a documentação abrangenté fácilitam o inicio.\nClojure possui uma curva mais ingreme que envolve aprender a sintaxe Lisp, pensar de forma funcional e adotar uma nova forma de modelar problemas. Para quem nunca trabalhou com Lisp, a adaptacao pode levar meses.\nCasos de uso recomendados Quando usar Kotlin Kotlin e indicado para desenvolvimento Android, APIs e microsservicos backend, aplicações multiplataforma, projetos com equipes de tamanhos variados e cenários que exigem tipagem estática e tooling avançado.\nQuando usar Clojure Clojure e indicada para sistemas com alta concorrência e estado compartilhado, processamento de dados e transformacoes complexas, equipes que valorizam programação funcional pura, projetos que se beneficiam de REPL-driven development e sistemas que requerem imutabilidade rigorosa.\nVeredicto Kotlin e Clojure servem a propositos diferentes e a escolha depende do contexto. Kotlin e a escolha pragmatica para a maioria dos projetos, com maior mercado e ecossistema mais amplo. Clojure e a escolha para equipes que abraccam a programação funcional e buscam as vantagens de imutabilidade e concorrência que a linguagem oferece de forma nativa. Para a maioria dos desenvolvedores brasileiros, Kotlin oferece mais oportunidades de carreira, enquanto Clojure e um investimento valioso para quem deseja se especializar em programação funcional. Se você está explorando linguagens com fortes recursos funcionais, veja também como Rust combina programação funcional com segurança de memória e como Python adota paradigmas funcionais com map, filter e reduce.\n","permalink":"https://kotlin.dev.br/comparacoes/kotlin-vs-clojure/","summary":"\u003ch2 id=\"kotlin-vs-clojure-em-2026-duas-filosofias-na-jvm\"\u003eKotlin vs Clojure em 2026: duas filosofias na JVM\u003c/h2\u003e\n\u003cp\u003eKotlin e Clojure representam abordagens radicalmente diferentes para desenvolvimento na JVM. Kotlin é uma linguagem multiparadigma com foco em pragmatismo, enquanto Clojure é um dialeto de Lisp com foco em programação funcional e imutabilidade. Este artigo compara as duas linguagens para ajudar você a entender onde cada uma se destaca.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracteristica\u003c/th\u003e\n          \u003cth\u003eKotlin\u003c/th\u003e\n          \u003cth\u003eClojure\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eParadigma\u003c/td\u003e\n          \u003ctd\u003eOO + Funcional\u003c/td\u003e\n          \u003ctd\u003eFuncional (Lisp)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTipagem\u003c/td\u003e\n          \u003ctd\u003eEstática\u003c/td\u003e\n          \u003ctd\u003eDinamica\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSintaxe\u003c/td\u003e\n          \u003ctd\u003eBaseada em C/Java\u003c/td\u003e\n          \u003ctd\u003eBaseada em Lisp (S-expressions)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCriador\u003c/td\u003e\n          \u003ctd\u003eJetBrains\u003c/td\u003e\n          \u003ctd\u003eRich Hickey\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAno\u003c/td\u003e\n          \u003ctd\u003e2016\u003c/td\u003e\n          \u003ctd\u003e2007\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eImutabilidade\u003c/td\u003e\n          \u003ctd\u003eOpcional (val/var)\u003c/td\u003e\n          \u003ctd\u003ePadrao\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eREPL\u003c/td\u003e\n          \u003ctd\u003eSim\u003c/td\u003e\n          \u003ctd\u003eSim (central ao workflow)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAndroid\u003c/td\u003e\n          \u003ctd\u003eSuporte oficial\u003c/td\u003e\n          \u003ctd\u003eLimitado\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"sintaxe-e-paradigma\"\u003eSintaxe e paradigma\u003c/h2\u003e\n\u003cp\u003eA diferenca mais visivel entre as linguagens é a sintaxe. Kotlin utiliza uma sintaxe familiar para desenvolvedores de Java e C:\u003c/p\u003e","title":"Kotlin vs Clojure: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Quanto ganha um desenvolvedor Android com Kotlin em 2026? O desenvolvimento Android com Kotlin se consolidou como uma das carreiras mais promissoras e bem remuneradas no mercado de tecnologia brasileiro. Desde que o Google declarou Kotlin como a linguagem preferida para Android, a demanda por profissionais especializados nessa combinacao não parou de crescer. Neste artigo, apresentamos as faixas salariais completas para desenvolvedores Android com Kotlin em 2026, considerando todos os niveis de experiência, regioes e regimes de contratacao.\nFaixa salarial por nível de experiência A remuneracao de um desenvolvedor Android com Kotlin varia significativamente conforme o nível de experiência do profissional:\nNível CLT (mensal) PJ (mensal) Remoto Internacional Junior (0-2 anos) R$ 3.500 - R$ 6.000 R$ 5.000 - R$ 8.500 USD 2.000 - USD 3.500 Pleno (2-5 anos) R$ 7.000 - R$ 13.000 R$ 10.000 - R$ 17.000 USD 3.500 - USD 6.000 Senior (5+ anos) R$ 13.000 - R$ 22.000 R$ 17.000 - R$ 30.000 USD 6.000 - USD 12.000 Esses valores refletem o mercado atual e incluem posicoes em empresas de diferentes portes e segmentos.\nVariacao por região São Paulo O maior polo tecnologico do pais oferece os salários mais elevados. Empresas como Nubank, iFood, Mercado Livre e diversas outras fintechs e unicornios disputam profissionais Android com propostas agressivas. Um desenvolvedor pleno em São Paulo pode esperar salários CLT entre R$ 9.000 e R$ 13.000 com facilidade.\nSul do Brasil Florianopolis se destaca como polo de tecnologia com salários competitivos. Curitiba e Porto Alegre também oferecem boas oportunidades, com salários CLT para pleno entre R$ 7.000 e R$ 11.000. A qualidade de vida dessas cidades é um atrativo adicional.\nNordeste O ecossistema tech nordestino esta em plena expansao. Recife, com o Porto Digital, e Fortaleza lideram as contratacoes. Salários CLT para pleno ficam entre R$ 6.500 e R$ 9.500, com tendencia de crescimento.\nRemoto O trabalho remoto eliminou barreiras geograficas. Profissionais em qualquer cidade brasileira podem acessar vagas com salários equivalentes aos de São Paulo quando trabalham para empresas que adotam politicas de remuneracao não atrelada a localização.\nHabilidades que impactam o salário Jetpack Compose O dominio de Jetpack Compose é o fator que mais impacta positivamente o salário de um desenvolvedor Android com Kotlin em 2026. Profissionais que dominam essa tecnologia de interface declarativa recebem propostas 15 a 25 por cento acima da media. Compose se tornou o padrão para desenvolvimento de UI no Android e empresas priorizam candidatos com experiência nessa ferramenta.\nArquitetura e design patterns Conhecimento solido em Clean Architecture, MVVM, MVI e principios SOLID diferencia profissionais e justifica salários mais altos. A capacidade de projetar aplicações modulares, testáveis e escalaveis e altamente valorizada.\nTestes automatizados Profissionais que escrevem testes unitarios com JUnit e MockK, testes de UI com Compose Testing e testes de integração se destacam no mercado. A cultura de testes ainda não e universal no Brasil, o que torna esse conhecimento um diferencial competitivo.\nKotlin Multiplatform O dominio de Kotlin Multiplatform Mobile é um diferencial crescente. Empresas que buscam compartilhar lógica de negócio entre Android e iOS pagam premios por profissionais com essa expertise.\nCI/CD e DevOps Experiência com pipelines de CI/CD, distribuição automatizada de builds, ferramentas como Fastlane e integração com Firebase complementam o perfil de um desenvolvedor Android completo.\nAnálise do mercado de trabalho O mercado para desenvolvedores Android com Kotlin em 2026 e robusto e diversificado. O Brasil possui uma das maiores bases de usuários Android do mundo, o que sustenta uma demanda constante por profissionais de desenvolvimento mobile.\nFintechs e bancos digitais continuam sendo os maiores empregadores, seguidos por empresas de e-commerce, delivery, mobilidade urbana e saude digital. Startups em estagio inicial também representam uma parcela significativa das vagas, frequentemente oferecendo equity como parte do pacote de remuneracao.\nUma tendencia relevante é o crescimento de vagas que combinam desenvolvimento Android com conhecimentos de backend ou multiplataforma. Profissionais full-stack mobile que conseguem transitar entre frontend e backend, ou entre Android e iOS via Kotlin Multiplatform, recebem propostas diferenciadas.\nBeneficios comuns além do salário Empresas de tecnologia no Brasil costumam oferecer pacotes de beneficios atrativos para desenvolvedores Android. Os mais comuns incluem plano de saude e odontologico premium, vale-refeicao ou alimentacao acima da media, orcamento para equipamentos e home office, subsidio para cursos e conferencias, horario flexivel e programa de participacao nos resultados.\nEsses beneficios podem representar um acrescimo de 25 a 40 por cento sobre o salário base e devem ser considerados na avaliacao de propostas.\nDicas para se destacar e ganhar mais Contribua para o ecossistema Publicar bibliotecas Android, contribuir para projetos open source como as bibliotecas do Jetpack ou escrever artigos tecnicos eleva sua visibilidade e abre portas para oportunidades premium.\nDomine o ciclo completo Profissionais que entendem desde o design de UI/UX até a publicacao na Google Play Store, passando por otimização de performance e monitoramento em producao, são mais valorizados que especialistas em apenas uma etapa do processo.\nMantenha-se atualizado O ecossistema Android evolui rapidamente. Acompanhe os lancamentos do Google I/O, as novidades do Kotlin e as atualizações do Jetpack. Profissionais atualizados são percebidos como mais valiosos.\nInvista em ingles O ingles fluente é o fator que mais amplia suas possibilidades de remuneracao. O acesso ao mercado internacional remoto pode multiplicar seu salário por dois a quatro vezes.\nPerspectivas para os próximos anos O desenvolvimento Android com Kotlin deve continuar em alta nos próximos anos. A adoção de Kotlin Multiplatform, a evolução do Jetpack Compose é a integração com novas plataformas como Wear OS e Android Auto ampliam as oportunidades. Profissionais que investem em aprendizado continuo e acompanham essas tendências estarao bem posicionados para as melhores oportunidades do mercado.\nConclusão O salário de um desenvolvedor Android com Kotlin no Brasil em 2026 varia de R$ 3.500 para juniors até R$ 30.000 ou mais para seniors no regime PJ. O mercado internacional remoto eleva ainda mais esse teto, com remuneracoes em dolar que podem ultrapassar R$ 60.000 mensais. A especializacao em Jetpack Compose, Kotlin Multiplatform e arquitetura de aplicações são os caminhos mais eficazes para alcancar as faixas salariais mais altas nessa carreira. Para comparar remunerações em outras tecnologias, confira os salários de desenvolvedores Go, Python e Rust no mercado brasileiro.\n","permalink":"https://kotlin.dev.br/carreira/salario-dev-android-kotlin/","summary":"\u003ch2 id=\"quanto-ganha-um-desenvolvedor-android-com-kotlin-em-2026\"\u003eQuanto ganha um desenvolvedor Android com Kotlin em 2026?\u003c/h2\u003e\n\u003cp\u003eO desenvolvimento Android com Kotlin se consolidou como uma das carreiras mais promissoras e bem remuneradas no mercado de tecnologia brasileiro. Desde que o Google declarou Kotlin como a linguagem preferida para Android, a demanda por profissionais especializados nessa combinacao não parou de crescer. Neste artigo, apresentamos as faixas salariais completas para desenvolvedores Android com Kotlin em 2026, considerando todos os niveis de experiência, regioes e regimes de contratacao.\u003c/p\u003e","title":"Salário de Desenvolvedor Android Kotlin: Quanto Ganha em 2026 | Kotlin Brasil"},{"content":"Kotlin Coroutines vs RxJava: programação assíncrona em 2026 A programação assíncrona e essencial no desenvolvimento moderno, seja para chamadas de rede, operações de banco de dados ou processamento em background. Durante anos, RxJava foi a solução dominante no ecossistema Android e JVM. Com a maturidade de Kotlin Coroutines e Flow, muitas equipes migraram ou consideram migrar. Este artigo compara as duas abordagens em profundidade.\nVisao geral Caracteristica Kotlin Coroutines RxJava Linguagem Kotlin nativo Java (com extensoes Kotlin) Paradigma Suspensao sequencial Streams reativos Curva de aprendizado Moderada Alta Backpressure Flow (nativo) Flowable (explicito) Integração Android Oficial (Jetpack) Biblioteca terceira Peso da dependência Leve (~1.5MB) Pesado (~3MB+) Suporte multiplatform Sim Apenas JVM Cancellamento Estruturado (scope) Manual (Disposable) Modelo de programação A diferenca fundamental esta na forma como cada abordagem expressa operações assíncronas.\nCoroutines: código sequencial com suspensao Coroutines permitem escrever código assíncrono que parece sincrono. A palavra-chave suspend marca funções que podem pausar sem bloquear a thread:\n// Coroutines: leitura natural, de cima para baixo suspend fun buscarPerfilCompleto(userId: Int): PerfilCompleto { val usuario = api.buscarUsuario(userId) // suspende val posts = api.buscarPosts(userId) // suspende val seguidores = api.buscarSeguidores(userId) // suspende return PerfilCompleto(usuario, posts, seguidores) } // Execução paralela quando necessario suspend fun buscarPerfilParalelo(userId: Int): PerfilCompleto = coroutineScope { val usuario = async { api.buscarUsuario(userId) } val posts = async { api.buscarPosts(userId) } val seguidores = async { api.buscarSeguidores(userId) } PerfilCompleto(usuario.await(), posts.await(), seguidores.await()) } RxJava: cadeias de operadores reativos RxJava modela tudo como streams de dados transformados por operadores:\n// RxJava: cadeia de operadores fun buscarPerfilCompleto(userId: Int): Single\u0026lt;PerfilCompleto\u0026gt; { return Single.zip( api.buscarUsuario(userId), api.buscarPosts(userId), api.buscarSeguidores(userId) ) { usuario, posts, seguidores -\u0026gt; PerfilCompleto(usuario, posts, seguidores) } } // Sequencial em RxJava fun buscarPerfilSequencial(userId: Int): Single\u0026lt;PerfilCompleto\u0026gt; { return api.buscarUsuario(userId) .flatMap { usuario -\u0026gt; api.buscarPosts(userId).map { posts -\u0026gt; usuario to posts } } .flatMap { (usuario, posts) -\u0026gt; api.buscarSeguidores(userId).map { seguidores -\u0026gt; PerfilCompleto(usuario, posts, seguidores) } } } A versão com Coroutines e significativamente mais legivel. A versão RxJava requer conhecimento de operadores como zip, flatMap e map para expressar a mesma lógica.\nTratamento de erros Coroutines: try/catch padrão suspend fun carregarDados(): Resultado { return try { val dados = api.buscar() Resultado.Sucesso(dados) } catch (e: HttpException) { Resultado.Erro(\u0026#34;Erro HTTP: ${e.code()}\u0026#34;) } catch (e: IOException) { Resultado.Erro(\u0026#34;Sem conexao\u0026#34;) } } RxJava: operadores de erro fun carregarDados(): Single\u0026lt;Resultado\u0026gt; { return api.buscar() .map\u0026lt;Resultado\u0026gt; { dados -\u0026gt; Resultado.Sucesso(dados) } .onErrorReturn { e -\u0026gt; when (e) { is HttpException -\u0026gt; Resultado.Erro(\u0026#34;Erro HTTP: ${e.code()}\u0026#34;) is IOException -\u0026gt; Resultado.Erro(\u0026#34;Sem conexao\u0026#34;) else -\u0026gt; Resultado.Erro(\u0026#34;Erro desconhecido\u0026#34;) } } } O try/catch de Coroutines e familiar para qualquer desenvolvedor. Em RxJava, você precisa conhecer onErrorReturn, onErrorResumeNext, retry e outros operadores específicos para tratamento de erros.\nCancelamento Coroutines: cancelamento estruturado class MinhaViewModel : ViewModel() { // viewModelScope cancela automaticamente quando ViewModel e destruido fun carregarDados() { viewModelScope.launch { val dados = repositorio.buscar() // cancelado automaticamente _estado.value = dados } } } // Cancelamento manual val job = scope.launch { while (isActive) { val dado = canal.receive() processar(dado) } } job.cancel() // cancela limpo RxJava: Disposable manual class MinhaViewModel : ViewModel() { private val disposables = CompositeDisposable() fun carregarDados() { disposables.add( repositorio.buscar() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( { dados -\u0026gt; _estado.value = dados }, { erro -\u0026gt; _estado.value = Estado.Erro(erro) } ) ) } override fun onCleared() { disposables.clear() // esqueceu? vazamento de memoria } } O cancelamento estruturado de Coroutines e uma vantagem significativa. Com viewModelScope, lifecycleScope e coroutineScope, o cancelamento e automatico e hierarquico. Em RxJava, esquecer de chamar dispose() e uma fonte comum de bugs e vazamentos.\nFluxos de dados reativos Kotlin Flow vs Observable/Flowable // Kotlin Flow fun observarUsuarios(): Flow\u0026lt;List\u0026lt;Usuario\u0026gt;\u0026gt; = flow { while (true) { val usuarios = api.buscarUsuarios() emit(usuarios) delay(30_000) // atualiza a cada 30 segundos } }.catch { e -\u0026gt; emit(emptyList()) }.flowOn(Dispatchers.IO) // Consumo lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.usuarios.collect { lista -\u0026gt; adapter.submitList(lista) } } } // RxJava Observable fun observarUsuarios(): Observable\u0026lt;List\u0026lt;Usuario\u0026gt;\u0026gt; { return Observable.interval(0, 30, TimeUnit.SECONDS) .flatMapSingle { api.buscarUsuarios() } .onErrorReturnItem(emptyList()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) } // Consumo disposables.add( viewModel.observarUsuarios() .subscribe { lista -\u0026gt; adapter.submitList(lista) } ) StateFlow vs BehaviorSubject // Kotlin StateFlow class ContadorViewModel : ViewModel() { private val _contador = MutableStateFlow(0) val contador: StateFlow\u0026lt;Int\u0026gt; = _contador.asStateFlow() fun incrementar() { _contador.value++ } } // RxJava BehaviorSubject class ContadorViewModel : ViewModel() { private val _contador = BehaviorSubject.createDefault(0) val contador: Observable\u0026lt;Int\u0026gt; = _contador.hide() fun incrementar() { _contador.onNext(_contador.value!! + 1) } } Performance Em benchmarks práticos, Coroutines geralmente apresentam menor uso de memória e latencia comparable ou inferior a RxJava para a maioria dos cenários. A principal razao e que coroutines suspensas não alocam objetos intermediarios na mesma proporcao que cadeias de operadores RxJava.\nMetrica Coroutines RxJava Memória por operação Baixa (state machine) Moderada (objetos Observable) Overhead de criação Minimo Moderado (cadeia de operadores) Troca de contexto Eficiente (Dispatchers) Schedulers (thread pool) Cold start Rapido Mais lento (setup da cadeia) Para cenários com milhares de operações concorrentes, coroutines escalam melhor porque cada coroutine ocupa poucos bytes na memória, enquanto cada subscription RxJava mantém uma cadeia de objetos.\nQuando usar cada um Escolha Kotlin Coroutines quando: Você inicia um projeto novo em Kotlin Precisa de integração nativa com Jetpack (ViewModel, Room, Compose) Quer código mais legivel é fácil de depurar Precisa de suporte Kotlin Multiplatform A equipe tem experiência limitada com programação reativa Cancelamento automatico e importante Escolha RxJava quando: O projeto existente já usa RxJava extensivamente Você precisa de operadores complexos de combinacao de streams que não tem equivalente direto em Flow A equipe já domina o modelo reativo Você trabalha com um codebase Java que não pode migrar para Kotlin Migração gradual Ambas as abordagens podem coexistir. A biblioteca kotlinx-coroutines-rx3 oferece funções de conversao:\n// RxJava para Flow val flow: Flow\u0026lt;String\u0026gt; = observable.asFlow() // Flow para Observable val observable: Observable\u0026lt;String\u0026gt; = flow.asObservable() // Single para suspend val resultado: String = single.await() Veredito Em 2026, Kotlin Coroutines com Flow e a escolha recomendada para novos projetos Kotlin. A integração com o ecossistema Android Jetpack e nativa, o modelo de cancelamento estruturado previne vazamentos, e o código resultante e mais legivel. RxJava permanece uma opção válida para projetos existentes que já investiram no modelo reativo, mas a tendencia clara do ecossistema e em direcao a Coroutines. Se você esta comecando hoje, invista seu tempo em dominar Coroutines e Flow. Para comparar modelos de concorrência além da JVM, veja como Go implementa concorrência com goroutines e channels e como Rust aborda async/await com segurança de memória garantida.\n","permalink":"https://kotlin.dev.br/comparacoes/kotlin-coroutines-vs-rxjava/","summary":"\u003ch2 id=\"kotlin-coroutines-vs-rxjava-programação-assíncrona-em-2026\"\u003eKotlin Coroutines vs RxJava: programação assíncrona em 2026\u003c/h2\u003e\n\u003cp\u003eA programação assíncrona e essencial no desenvolvimento moderno, seja para chamadas de rede, operações de banco de dados ou processamento em background. Durante anos, RxJava foi a solução dominante no ecossistema Android e JVM. Com a maturidade de Kotlin Coroutines e Flow, muitas equipes migraram ou consideram migrar. Este artigo compara as duas abordagens em profundidade.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracteristica\u003c/th\u003e\n          \u003cth\u003eKotlin Coroutines\u003c/th\u003e\n          \u003cth\u003eRxJava\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eLinguagem\u003c/td\u003e\n          \u003ctd\u003eKotlin nativo\u003c/td\u003e\n          \u003ctd\u003eJava (com extensoes Kotlin)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eParadigma\u003c/td\u003e\n          \u003ctd\u003eSuspensao sequencial\u003c/td\u003e\n          \u003ctd\u003eStreams reativos\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCurva de aprendizado\u003c/td\u003e\n          \u003ctd\u003eModerada\u003c/td\u003e\n          \u003ctd\u003eAlta\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eBackpressure\u003c/td\u003e\n          \u003ctd\u003eFlow (nativo)\u003c/td\u003e\n          \u003ctd\u003eFlowable (explicito)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eIntegração Android\u003c/td\u003e\n          \u003ctd\u003eOficial (Jetpack)\u003c/td\u003e\n          \u003ctd\u003eBiblioteca terceira\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePeso da dependência\u003c/td\u003e\n          \u003ctd\u003eLeve (~1.5MB)\u003c/td\u003e\n          \u003ctd\u003ePesado (~3MB+)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSuporte multiplatform\u003c/td\u003e\n          \u003ctd\u003eSim\u003c/td\u003e\n          \u003ctd\u003eApenas JVM\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCancellamento\u003c/td\u003e\n          \u003ctd\u003eEstruturado (scope)\u003c/td\u003e\n          \u003ctd\u003eManual (Disposable)\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"modelo-de-programação\"\u003eModelo de programação\u003c/h2\u003e\n\u003cp\u003eA diferenca fundamental esta na forma como cada abordagem expressa operações assíncronas.\u003c/p\u003e","title":"Kotlin Coroutines vs RxJava: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Kotlin vs Groovy em 2026: comparação completa Kotlin e Groovy são linguagens JVM que surgiram como alternativas ao Java, mas com filosofias bastante diferentes. Groovy foi pioneira como linguagem de scripting e DSLs na JVM, enquanto Kotlin trouxe tipagem estática moderna com produtividade de linguagens dinamicas. Este artigo analisa ambas as linguagens para ajudar você a escolher a mais adequada em 2026.\nVisao geral Caracteristica Kotlin Groovy Tipagem Estática Dinamica e estática Null safety Nativo Nao Performance Alta (compilação estática) Variavel Uso principal em 2026 Apps, backend, multiplatform Gradle, scripting, Jenkins Criador JetBrains James Strachan (Apache) Android Suporte oficial Nao suportado IDE IntelliJ IDEA IntelliJ IDEA Tipagem: estática versus dinâmica A diferenca fundamental entre Kotlin e Groovy esta no sistema de tipos.\nKotlin utiliza tipagem estática com inferencia:\nval nome = \u0026#34;Kotlin\u0026#34; // tipo inferido como String val idade: Int = 25 // tipo explicito // nome = 42 // erro de compilacao! fun somar(a: Int, b: Int): Int = a + b Groovy utiliza tipagem dinâmica por padrão, com opção de tipagem estática:\ndef nome = \u0026#34;Groovy\u0026#34; // tipo dinamico nome = 42 // valido em Groovy! def somar(a, b) { a + b } // aceita qualquer tipo // Com tipagem estática opcional @CompileStatic int somarEstatico(int a, int b) { a + b } A tipagem estática de Kotlin oferece deteccao de erros em tempo de compilação, melhor suporte de IDE com autocompletar e refatoração, e performance previsivel. A tipagem dinâmica de Groovy oferece flexibilidade para scripting e DSLs, menos código boilerplate em scripts simples, é fácilidade para metaprogramação.\nNull safety Kotlin possui null safety integrado ao sistema de tipos:\nvar texto: String = \u0026#34;seguro\u0026#34; // texto = null // erro de compilacao var nulavel: String? = null val tamanho = nulavel?.length ?: 0 Groovy não possui null safety nativo, mas oferece o operador safe navigation:\nString texto = null def tamanho = texto?.length() ?: 0 // funciona, mas sem garantia de compilacao A abordagem de Kotlin e superior porque o compilador garante que você trate todos os casos de nulabilidade, eliminando NullPointerException em tempo de compilação.\nPerformance A diferenca de performance entre Kotlin e Groovy pode ser significativa:\nAspecto Kotlin Groovy Invocacao de métodos Direta (estática) Dynamic dispatch Startup Rapido Mais lento Throughput Alto Menor (modo dinamico) Com @CompileStatic N/A Proximo ao Java Memória Eficiente Maior overhead Groovy com a anotacao @CompileStatic se aproxima da performance de Java e Kotlin, mas o modo padrão dinamico e significativamente mais lento para operações computacionalmente intensivas.\nGradle: o campo de batalha O caso de uso mais direto de comparação entre Kotlin e Groovy e o Gradle, onde ambas são usadas como linguagens de build script.\nGroovy foi a linguagem original do Gradle:\nplugins { id \u0026#39;org.jetbrains.kotlin.jvm\u0026#39; version \u0026#39;2.1.0\u0026#39; } dependencies { implementation \u0026#39;org.jetbrains.kotlin:kotlin-stdlib\u0026#39; testImplementation \u0026#39;junit:junit:4.13.2\u0026#39; } task customTask { doLast { println \u0026#39;Executando task customizada\u0026#39; } } Kotlin DSL para Gradle:\nplugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.1.0\u0026#34; } dependencies { implementation(kotlin(\u0026#34;stdlib\u0026#34;)) testImplementation(\u0026#34;junit:junit:4.13.2\u0026#34;) } tasks.register(\u0026#34;customTask\u0026#34;) { doLast { println(\u0026#34;Executando task customizada\u0026#34;) } } O Kotlin DSL oferece autocompletar completo no IDE, deteccao de erros em tempo de edicao, navegação para definicoes de funções e documentação inline. O Groovy DSL e mais conciso em alguns casos e possui mais exemplos e documentação disponivel, mas a tendencia e de migração para Kotlin DSL em novos projetos.\nScripting e automação Groovy foi projetada como linguagem de script e brilha nesse caso de uso. Jenkins pipelines, scripts de automação e processamento de dados são areas onde Groovy e amplamente utilizada.\nKotlin também suporta scripting com arquivos .kts, mas o ecossistema de scripting e menos maduro:\n// script.kts val arquivos = java.io.File(\u0026#34;.\u0026#34;).listFiles() arquivos?.filter { it.extension == \u0026#34;kt\u0026#34; } ?.forEach { println(it.name) } Para automação rápida e scripts simples, Groovy ainda oferece uma experiência mais fluida. Para projetos maiores que comecam como scripts e podem crescer, Kotlin oferece mais segurança e escalabilidade.\nDSLs (Domain-Specific Languages) Ambas as linguagens são excelentes para criação de DSLs, mas com abordagens diferentes. Groovy utiliza metaprogramação e tipagem dinâmica para criar DSLs extremamente flexiveis. Kotlin utiliza lambdas com receiver e extension functions para criar DSLs type-safe.\nA abordagem de Kotlin e mais segura e oferece melhor suporte de IDE, enquanto a de Groovy e mais flexivel e requer menos boilerplate para DSLs simples.\nMercado de trabalho O mercado para Kotlin e significativamente maior que para Groovy em 2026. Kotlin domina em desenvolvimento Android, backend e multiplataforma, com milhares de vagas disponiveis. Groovy concentra suas oportunidades em engenharia de DevOps com Jenkins, manutenção de projetos Gradle e automação empresarial.\nProfissionais que dominam Groovy geralmente a utilizam como habilidade complementar, não como especializacao principal. Ja Kotlin e frequentemente a habilidade central de uma carreira.\nCasos de uso recomendados Quando usar Kotlin Kotlin e a melhor escolha para desenvolvimento de aplicações Android, backend com Spring Boot ou Ktor, projetos multiplataforma, Gradle build scripts em novos projetos e qualquer projeto JVM de médio a grande porte.\nQuando usar Groovy Groovy e preferivel para Jenkins pipelines e automação DevOps, scripts rápidos de processamento de dados, manutenção de projetos Gradle existentes em Groovy, prototipagem rápida que se beneficia de tipagem dinâmica e testes com frameworks como Spock.\nVeredicto Em 2026, Kotlin e claramente a linguagem mais relevante para desenvolvimento de aplicações e a escolha padrão para novos projetos JVM. Groovy mantém um papel importante em nicho de DevOps, scripting e automação, onde sua natureza dinâmica e uma vantagem. Para a maioria dos desenvolvedores, investir em Kotlin oferece um retorno de carreira significativamente maior, enquanto conhecer Groovy como habilidade complementar pode ser útil em contextos específicos. Se você busca alternativas modernas à JVM, Go oferece simplicidade e performance para backend e Python domina em ciência de dados e automação.\n","permalink":"https://kotlin.dev.br/comparacoes/kotlin-vs-groovy/","summary":"\u003ch2 id=\"kotlin-vs-groovy-em-2026-comparação-completa\"\u003eKotlin vs Groovy em 2026: comparação completa\u003c/h2\u003e\n\u003cp\u003eKotlin e Groovy são linguagens JVM que surgiram como alternativas ao Java, mas com filosofias bastante diferentes. Groovy foi pioneira como linguagem de scripting e DSLs na JVM, enquanto Kotlin trouxe tipagem estática moderna com produtividade de linguagens dinamicas. Este artigo analisa ambas as linguagens para ajudar você a escolher a mais adequada em 2026.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracteristica\u003c/th\u003e\n          \u003cth\u003eKotlin\u003c/th\u003e\n          \u003cth\u003eGroovy\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTipagem\u003c/td\u003e\n          \u003ctd\u003eEstática\u003c/td\u003e\n          \u003ctd\u003eDinamica e estática\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eNull safety\u003c/td\u003e\n          \u003ctd\u003eNativo\u003c/td\u003e\n          \u003ctd\u003eNao\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePerformance\u003c/td\u003e\n          \u003ctd\u003eAlta (compilação estática)\u003c/td\u003e\n          \u003ctd\u003eVariavel\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eUso principal em 2026\u003c/td\u003e\n          \u003ctd\u003eApps, backend, multiplatform\u003c/td\u003e\n          \u003ctd\u003eGradle, scripting, Jenkins\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCriador\u003c/td\u003e\n          \u003ctd\u003eJetBrains\u003c/td\u003e\n          \u003ctd\u003eJames Strachan (Apache)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAndroid\u003c/td\u003e\n          \u003ctd\u003eSuporte oficial\u003c/td\u003e\n          \u003ctd\u003eNao suportado\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eIDE\u003c/td\u003e\n          \u003ctd\u003eIntelliJ IDEA\u003c/td\u003e\n          \u003ctd\u003eIntelliJ IDEA\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"tipagem-estática-versus-dinâmica\"\u003eTipagem: estática versus dinâmica\u003c/h2\u003e\n\u003cp\u003eA diferenca fundamental entre Kotlin e Groovy esta no sistema de tipos.\u003c/p\u003e","title":"Kotlin vs Groovy: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Quanto ganha um desenvolvedor Kotlin senior em 2026? O desenvolvedor Kotlin senior é um dos profissionais mais valorizados no mercado de tecnologia brasileiro. Com experiência solida, capacidade de lideranca técnica e dominio profundo da linguagem e seu ecossistema, esse profissional tem acesso a oportunidades com remuneracoes que figuram entre as mais altas do setor. Neste artigo, detalhamos as faixas salariais, habilidades exigidas e estrategias para maximizar seus ganhos como desenvolvedor Kotlin senior em 2026.\nFaixa salarial media no Brasil O nível senior compreende profissionais com cinco ou mais anos de experiência relevante, capacidade de tomar decisoes arquiteturais e histórico comprovado de entrega em projetos de alta complexidade.\nRegime Faixa Salarial Mensal Media Nacional CLT R$ 12.000 - R$ 22.000 R$ 16.000 PJ R$ 16.000 - R$ 30.000 R$ 22.000 Remoto Internacional USD 6.000 - USD 12.000 USD 8.500 Essas faixas posicionam o desenvolvedor Kotlin senior como um dos profissionais mais bem remunerados no cenário de desenvolvimento de software no Brasil.\nVariacao por região e tipo de empresa São Paulo A maior cidade da America Latina concentra a maior parte das vagas de alto nível. Grandes empresas de tecnologia, bancos digitais e unicornios oferecem salários CLT entre R$ 15.000 e R$ 22.000 para seniors. No regime PJ, os valores podem chegar a R$ 30.000 em empresas de ponta.\nDemais capitais Rio de Janeiro, Belo Horizonte, Curitiba e Porto Alegre apresentam faixas CLT entre R$ 12.000 e R$ 18.000. Florianopolis, apesar de ser uma cidade menor, possui um ecossistema de startups que oferece remuneracoes competitivas, frequentemente alinhadas com os valores de São Paulo.\nEmpresas internacionais remotas O segmento que mais cresceu nos ultimos anos é o de vagas remotas para empresas internacionais. Desenvolvedores senior brasileiros que trabalham para empresas americanas e europeias recebem entre USD 6.000 e USD 12.000 por mes. Convertidos para reais, esses valores representam uma remuneracao excepcional e estao acessiveis para profissionais com ingles fluente e experiência comprovada.\nStartups versus corporacoes Startups tendem a oferecer salários base ligeiramente menores, porem complementam com equity e stock options que podem representar ganhos substanciais a longo prazo. Corporacoes e empresas estabelecidas geralmente oferecem salários base mais altos, bonus por performance e pacotes de beneficios robustos.\nHabilidades que definem um senior Expertise técnica profunda O desenvolvedor Kotlin senior deve ter dominio completo da linguagem, incluindo funcionalidades avançadas como DSLs internas, metaprogramação com KSP e kapt, generics avançados com variancia e type projections. Experiência com arquitetura de sistemas distribuidos, microsservicos e design de APIs escalaveis e fundamental.\nPara o ecossistema Android, dominio de Jetpack Compose em nível avançado, otimização de performance, gerenciamento de estado complexo e deep linking são expectativas comuns. No backend, experiência com Ktor ou Spring Boot em producao, integração com mensageria, cache distribuído e observabilidade são requisitos frequentes.\nLideranca técnica Mais do que escrever código de qualidade, o senior e responsavel por definir padrões arquiteturais, conduzir decisoes tecnicas e mentorar outros membros da equipe. A capacidade de avaliar tradeoffs, documentar decisoes e comunicar estrategias tecnicas para stakeholders não tecnicos e essencial.\nVisao de produto Seniors eficazes entendem o negócio por tras do código. Eles conseguem alinhar decisoes tecnicas com objetivos de produto, priorizar debito técnico de forma estrategica e contribuir para discussoes sobre roadmap e prioridades.\nAnálise do mercado para seniors O mercado para desenvolvedores Kotlin senior em 2026 e caracterizado por uma escassez cronica de profissionais. A demanda excede significativamente a oferta, o que mantém os salários em trajetoria ascendente e da aos profissionais grande poder de negociacao.\nOs setores que mais contratam incluem fintechs e bancos digitais, que lideram em volume de vagas e remuneracao. Empresas de e-commerce, healthtechs e plataformas de logistica também disputam profissionais senior com propostas agressivas. O setor publico, embora tradicionalmente mais conservador, tem modernizado suas plataformas e aberto oportunidades interessantes.\nA adoção crescente de Kotlin Multiplatform por empresas que buscam unificar suas bases de código entre plataformas criou um nicho particularmente lucrativo para seniors que dominam essa tecnologia.\nEstrategias para maximizar sua remuneracao Posicione-se como especialista Profissionais que são reconhecidos como referência em um nicho específico de Kotlin recebem propostas premium. Seja Kotlin Multiplatform, performance de aplicações Android ou arquitetura de microsservicos com Ktor, a especializacao profunda e recompensada pelo mercado.\nConstrua sua marca pessoal Palestras em conferencias, artigos tecnicos, contribuicoes para projetos open source e presenca ativa em comunidades como a Kotlin Brasil elevam sua visibilidade profissional. Recrutadores e empresas frequentemente abordam profissionais com presenca publica consolidada com propostas acima da media.\nExplore o mercado internacional Se você tem ingles fluente, o mercado internacional remoto pode oferecer remuneracoes duas a quatro vezes superiores ao mercado local. Plataformas como Toptal, Turing e contratacao direta por empresas americanas e europeias são canais estabelecidos para acessar essas oportunidades.\nNegocie pacotes completos Alem do salário base, negocie bonus, stock options, orcamento para conferencias e treinamento, horario flexivel e dias adicionais de ferias. O pacote total de compensacao pode representar um acrescimo de 20 a 50 por cento sobre o salário base.\nConsidere posicoes de staff engineer A carreira técnica além do senior, incluindo posicoes como staff engineer e principal engineer, oferece remuneracoes ainda maiores para profissionais que preferem não migrar para gestao. Essas posicoes focam em influencia técnica ampla e solução de problemas de alta complexidade.\nCLT versus PJ no nível senior Para seniors, a análise entre CLT e PJ se torna mais favoravel ao regime PJ na maioria dos casos. A diferenca entre propostas CLT e PJ costuma ser substancial nesse nível, é o profissional senior geralmente tem maturidade financeira para gerenciar os aspectos tributarios e previdenciarios do regime PJ.\nAinda assim, algumas corporacoes oferecem pacotes CLT extremamente competitivos com PLR, stock options e beneficios premium que podem equiparar ou superar propostas PJ. A análise deve ser feita caso a caso, considerando todos os componentes da remuneracao.\nPerspectivas futuras O desenvolvedor Kotlin senior esta bem posicionado para os próximos anos. A linguagem continua expandindo seu alcance para novas plataformas e dominios, o que garante relevancia e demanda no longo prazo. Profissionais que investem em aprendizado continuo e acompanham a evolução do ecossistema Kotlin manterao sua posicao privilegiada no mercado.\nConclusão O salário de um desenvolvedor Kotlin senior no Brasil em 2026 varia de R$ 12.000 a R$ 30.000 no mercado nacional, podendo ultrapassar R$ 50.000 em posicoes remotas internacionais. A combinacao de escassez de profissionais qualificados, demanda crescente e expansao do ecossistema Kotlin cria um cenário extremamente favoravel para profissionais nesse nível. Investir em especializacao, marca pessoal e posicionamento estrategico são as chaves para acessar as melhores oportunidades do mercado. Para comparar com outras linguagens, confira os salários de desenvolvedores Go, desenvolvedores Python e desenvolvedores Rust no Brasil.\n","permalink":"https://kotlin.dev.br/carreira/salario-dev-kotlin-senior/","summary":"\u003ch2 id=\"quanto-ganha-um-desenvolvedor-kotlin-senior-em-2026\"\u003eQuanto ganha um desenvolvedor Kotlin senior em 2026?\u003c/h2\u003e\n\u003cp\u003eO desenvolvedor Kotlin senior é um dos profissionais mais valorizados no mercado de tecnologia brasileiro. Com experiência solida, capacidade de lideranca técnica e dominio profundo da linguagem e seu ecossistema, esse profissional tem acesso a oportunidades com remuneracoes que figuram entre as mais altas do setor. Neste artigo, detalhamos as faixas salariais, habilidades exigidas e estrategias para maximizar seus ganhos como desenvolvedor Kotlin senior em 2026.\u003c/p\u003e","title":"Salário de Desenvolvedor Kotlin Senior: Quanto Ganha em 2026 | Kotlin Brasil"},{"content":"Kotlin vs Scala em 2026: qual linguagem JVM escolher? Kotlin e Scala são duas linguagens modernas que rodam na JVM e oferecem alternativas ao Java com abordagens diferentes. Enquanto Kotlin foca em pragmatismo e produtividade, Scala enfatiza a programação funcional é a expressividade do sistema de tipos. Este artigo compara as duas linguagens em profundidade para ajudar você a escolher a melhor opção para seus projetos e carreira.\nVisao geral Caracteristica Kotlin Scala Criador JetBrains Martin Odersky (EPFL) Ano de lancamento 2016 2004 Paradigma principal OO + Funcional pragmatico Funcional + OO Curva de aprendizado Moderada Ingreme Sistema de tipos Estatico com inferencia Estatico avançado Null safety Nativo Option type Android Suporte oficial Limitado Build tool Gradle sbt Sintaxe e expressividade Kotlin prioriza clareza e legibilidade. A sintaxe e projetada para ser intuitiva, especialmente para desenvolvedores vindos de Java:\ndata class Usuario(val nome: String, val idade: Int) fun filtrarAdultos(usuarios: List\u0026lt;Usuario\u0026gt;): List\u0026lt;String\u0026gt; { return usuarios .filter { it.idade \u0026gt;= 18 } .map { it.nome } .sorted() } Scala oferece maior expressividade e flexibilidade sintatica, mas pode ser mais difícil de ler para iniciantes:\ncase class Usuario(nome: String, idade: Int) def filtrarAdultos(usuarios: List[Usuario]): List[String] = usuarios .filter(_.idade \u0026gt;= 18) .map(_.nome) .sorted Neste exemplo simples, as linguagens são similares. Porem, Scala permite construcoes muito mais complexas com implicits, type classes e macros que não tem equivalente direto em Kotlin.\nProgramação funcional Scala e uma linguagem funcional com suporte a objetos. Kotlin e uma linguagem orientada a objetos com suporte funcional. Essa diferenca filosofica se manifesta em vários aspectos.\nScala oferece recursos funcionais avançados como pattern matching exaustivo, for comprehensions para composição monadica, type classes via implicits (ou givens no Scala 3), tipos algebricos com case classes e sealed traits, e higher-kinded types.\nKotlin oferece funcionalidades funcionais práticas incluindo lambdas e higher-order functions, extension functions, sealed classes e when expressions, inline functions para zero overhead, e operadores de colecao ricos.\nPara equipes que valorizam programação funcional pura e estao dispostas a investir na curva de aprendizado, Scala oferece ferramentas mais poderosas. Para equipes que buscam um equilibrio pragmatico entre OO e funcional, Kotlin e a escolha mais acessivel.\nNull safety versus Option Kotlin trata nulabilidade no sistema de tipos:\nfun encontrarUsuario(id: Int): Usuario? { return repositorio.buscar(id) } val nome = encontrarUsuario(1)?.nome ?: \u0026#34;Desconhecido\u0026#34; Scala utiliza o tipo Option para representar valores opcionais:\ndef encontrarUsuario(id: Int): Option[Usuario] = { repositorio.buscar(id) } val nome = encontrarUsuario(1).map(_.nome).getOrElse(\u0026#34;Desconhecido\u0026#34;) Ambas as abordagens eliminam NullPointerException, mas a de Kotlin e mais direta e familiar para desenvolvedores Java. A abordagem de Scala com Option e mais funcional e se integra melhor com for comprehensions.\nPerformance Ambas compilam para bytecode JVM, resultando em performance de runtime similar:\nAspecto Kotlin Scala Runtime Equivalente (JVM) Equivalente (JVM) Compilação Mais rápido Mais lento Tamanho do runtime Menor Maior Startup Similar Similar Otimização funcional Inline functions Especialization O compilador de Scala historicamente foi mais lento que o de Kotlin, embora o Scala 3 tenha trazido melhorias. O runtime de Scala também adiciona mais dependências ao projeto.\nEcossistema e frameworks O ecossistema de Kotlin inclui Spring Boot que e o framework web mais popular na JVM, Ktor como framework nativo Kotlin, Jetpack Compose para Android, e Kotlin Multiplatform para desenvolvimento multiplataforma.\nO ecossistema de Scala inclui Akka para sistemas distribuidos e concorrentes, Play Framework para aplicações web, Apache Spark que e o padrão para processamento de dados em larga escala, e ZIO e Cats Effect para programação funcional pura.\nScala possui uma vantagem clara no ecossistema de big data e processamento distribuído, gracas ao Apache Spark. Para desenvolvimento web e mobile, Kotlin oferece um ecossistema mais abrangente.\nMercado de trabalho No Brasil, Kotlin possui significativamente mais vagas que Scala. O mercado de Kotlin e impulsionado pelo desenvolvimento Android e pelo crescimento no backend. Scala concentra suas vagas em empresas de big data, fintechs que utilizam Akka e empresas de engenharia de dados.\nOs salários de Scala tendem a ser ligeiramente superiores aos de Kotlin no mesmo nível, refletindo a menor oferta de profissionais e a complexidade da linguagem. Porem, o volume de oportunidades e consideravelmente menor.\nCurva de aprendizado Kotlin foi projetado para ter uma curva de aprendizado suave, especialmente para desenvolvedores Java. A maioria dos profissionais consegue ser produtiva em Kotlin em poucas semanas.\nScala possui uma curva de aprendizado significativamente mais ingreme. Dominar conceitos como implicits, type classes, monads e o sistema de tipos avançado pode levar meses. Scala 3 simplificou alguns aspectos, mas a linguagem continua sendo uma das mais complexas do ecossistema JVM.\nCasos de uso recomendados Quando usar Kotlin Kotlin e a melhor escolha para desenvolvimento Android, aplicações web e APIs com Spring Boot ou Ktor, projetos multiplataforma, equipes com desenvolvedores de niveis variados de experiência e projetos que precisam de rápida entrega de valor.\nQuando usar Scala Scala e preferivel para processamento de dados em larga escala com Spark, sistemas distribuidos que se beneficiam de Akka, projetos onde programação funcional pura e uma prioridade, equipes com expertise em programação funcional e engenharia de dados e data pipelines.\nVeredicto Em 2026, Kotlin e a escolha mais versail e pragmatica para a maioria dos projetos na JVM. Sua curva de aprendizado acessivel, mercado amplo e ecossistema abrangente a tornam a recomendacao padrão. Scala mantém seu espaco em nichos específicos como big data e programação funcional avançada, onde suas ferramentas são superiores. Para quem considera alternativas fora da JVM, Go e Rust são opções modernas com ecossistemas crescentes no Brasil. A escolha entre as duas depende fundamentalmente do tipo de projeto e da filosofia da equipe.\n","permalink":"https://kotlin.dev.br/comparacoes/kotlin-vs-scala/","summary":"\u003ch2 id=\"kotlin-vs-scala-em-2026-qual-linguagem-jvm-escolher\"\u003eKotlin vs Scala em 2026: qual linguagem JVM escolher?\u003c/h2\u003e\n\u003cp\u003eKotlin e Scala são duas linguagens modernas que rodam na JVM e oferecem alternativas ao Java com abordagens diferentes. Enquanto Kotlin foca em pragmatismo e produtividade, Scala enfatiza a programação funcional é a expressividade do sistema de tipos. Este artigo compara as duas linguagens em profundidade para ajudar você a escolher a melhor opção para seus projetos e carreira.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracteristica\u003c/th\u003e\n          \u003cth\u003eKotlin\u003c/th\u003e\n          \u003cth\u003eScala\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCriador\u003c/td\u003e\n          \u003ctd\u003eJetBrains\u003c/td\u003e\n          \u003ctd\u003eMartin Odersky (EPFL)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAno de lancamento\u003c/td\u003e\n          \u003ctd\u003e2016\u003c/td\u003e\n          \u003ctd\u003e2004\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eParadigma principal\u003c/td\u003e\n          \u003ctd\u003eOO + Funcional pragmatico\u003c/td\u003e\n          \u003ctd\u003eFuncional + OO\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCurva de aprendizado\u003c/td\u003e\n          \u003ctd\u003eModerada\u003c/td\u003e\n          \u003ctd\u003eIngreme\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSistema de tipos\u003c/td\u003e\n          \u003ctd\u003eEstatico com inferencia\u003c/td\u003e\n          \u003ctd\u003eEstatico avançado\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eNull safety\u003c/td\u003e\n          \u003ctd\u003eNativo\u003c/td\u003e\n          \u003ctd\u003eOption type\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAndroid\u003c/td\u003e\n          \u003ctd\u003eSuporte oficial\u003c/td\u003e\n          \u003ctd\u003eLimitado\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eBuild tool\u003c/td\u003e\n          \u003ctd\u003eGradle\u003c/td\u003e\n          \u003ctd\u003esbt\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"sintaxe-e-expressividade\"\u003eSintaxe e expressividade\u003c/h2\u003e\n\u003cp\u003eKotlin prioriza clareza e legibilidade. A sintaxe e projetada para ser intuitiva, especialmente para desenvolvedores vindos de Java:\u003c/p\u003e","title":"Kotlin vs Scala: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Quanto ganha um desenvolvedor Kotlin pleno em 2026? O nível pleno representa uma fase crucial na carreira de um desenvolvedor Kotlin. E nesse estagio que o profissional consolida seus conhecimentos tecnicos, assume responsabilidades maiores em projetos e experimenta um salto significativo na remuneracao. Se você já tem entre dois e cinco anos de experiência com Kotlin e quer entender como esta o mercado, este artigo traz todas as informações que você precisa sobre salários, habilidades e oportunidades em 2026.\nFaixa salarial media no Brasil O desenvolvedor Kotlin pleno esta em uma posicao privilegiada no mercado brasileiro. A demanda por profissionais nesse nível e alta porque as empresas precisam de pessoas que consigam entregar com autonomia e qualidade. As faixas salariais em 2026 estao distribuidas assim:\nRegime Faixa Salarial Mensal Media Nacional CLT R$ 6.500 - R$ 12.000 R$ 8.800 PJ R$ 9.000 - R$ 16.000 R$ 12.000 Esses valores refletem profissionais com experiência comprovada em projetos reais, dominio de boas práticas e capacidade de trabalhar com autonomia dentro de equipes de desenvolvimento.\nVariacao por região Embora o trabalho remoto tenha se consolidado como tendencia no mercado de tecnologia, a localização da empresa contratante ainda influencia a remuneracao oferecida.\nSão Paulo e Grande SP A capital paulista continua liderando os salários para desenvolvedores Kotlin pleno. No regime CLT, os valores ficam entre R$ 8.500 e R$ 12.000. Para PJ, a faixa vai de R$ 12.000 a R$ 16.000. Empresas de tecnologia, fintechs e grandes corporacoes são os principais empregadores.\nRio de Janeiro O mercado carioca oferece salários CLT entre R$ 7.000 e R$ 10.500. Empresas do setor de midia, telecomunicacoes e financeiro são destaques na contratacao de profissionais Kotlin.\nSul do Brasil Florianopolis, Curitiba e Porto Alegre apresentam faixas CLT entre R$ 6.500 e R$ 9.500. A região sul se destaca pelo número crescente de startups e empresas de software que adotam Kotlin.\nNordeste Recife, Fortaleza e Salvador oferecem salários CLT entre R$ 6.000 e R$ 8.500. O ecossistema de tecnologia da região esta em crescimento acelerado, com destaque para hubs de inovacao.\nTrabalho remoto para empresas do exterior Profissionais pleno que trabalham remotamente para empresas internacionais podem receber entre USD 3.000 e USD 5.000 mensais, o que representa uma remuneracao significativamente superior ao mercado local.\nHabilidades exigidas para o nível pleno O desenvolvedor Kotlin pleno precisa ir além dos fundamentos da linguagem. As empresas esperam um conjunto mais amplo de competencias tecnicas e comportamentais.\nCompetencias tecnicas No nível pleno, você deve dominar design patterns aplicados em Kotlin, arquiteturas como MVVM, Clean Architecture e MVI para projetos Android, ou arquitetura hexagonal e DDD para backend. O conhecimento aprofundado de coroutines e flows e essencial, assim como experiência prática com testes unitarios, de integração e instrumentados.\nPara desenvolvedores Android, espera-se dominio de Jetpack Compose, Navigation Component, WorkManager e integração com APIs REST e GraphQL. No backend, conhecimentos em Spring Boot com Kotlin, Ktor, mensageria com Kafka ou RabbitMQ e bancos de dados relacionais e NoSQL são altamente valorizados.\nCompetencias comportamentais Alem da técnica, o profissional pleno deve demonstrar autonomia para resolver problemas, capacidade de fazer code review construtivo, mentoria informal de juniors e comunicação eficiente com stakeholders. A habilidade de estimar prazos com razoavel precisao e tomar decisoes tecnicas fundamentadas também e esperada.\nAnálise do mercado de trabalho O mercado para desenvolvedores Kotlin pleno em 2026 e extremamente favoravel. A consolidacao de Kotlin como linguagem preferida para Android e seu crescimento no backend criaram uma demanda que supera a oferta de profissionais qualificados nesse nível.\nSetores como fintechs, healthtechs, e-commerce e logistica lideram as contratacoes. Bancos tradicionais em processo de modernizacao tecnologica também representam uma fatia relevante das vagas. Empresas internacionais com operação remota no Brasil complementam o cenário com oportunidades de remuneracao diferenciada.\nUma tendencia importante é a valorizacao de profissionais que dominam Kotlin Multiplatform. A capacidade de desenvolver solucoes compartilhadas entre Android, iOS, web e backend com uma única linguagem é um diferencial competitivo cada vez mais relevante.\nCLT versus PJ para nível pleno No nível pleno, a decisao entre CLT e PJ se torna mais complexa e merece uma análise cuidadosa.\nNo regime CLT, os beneficios acumulados podem representar um acrescimo de 30 a 45 por cento sobre o salário bruto, incluindo decimo terceiro, ferias, FGTS, participacao nos lucros, plano de saude e vale-refeicao. Para um salário de R$ 10.000 CLT, o custo total para a empresa gira em torno de R$ 14.000 a R$ 15.000.\nNo regime PJ, e preciso considerar impostos que variam entre 6 e 15 por cento dependendo do enquadramento tributario, além de custos com contador, previdencia privada e plano de saude. Mesmo assim, para muitos profissionais pleno, o regime PJ oferece uma remuneracao liquida superior, especialmente quando a diferenca entre as propostas CLT e PJ e significativa.\nDicas para maximizar seu salário como pleno Especialize-se em nichos de alta demanda Profissionais que dominam Kotlin Multiplatform, Jetpack Compose avançado ou arquiteturas de microsservicos com Kotlin tendem a receber propostas acima da media do mercado.\nMantenha seu perfil atualizado LinkedIn e GitHub são vitrines profissionais. Mantenha seus projetos atualizados, publique artigos tecnicos e compartilhe conhecimento. Recrutadores utilizam essas plataformas ativamente para identificar candidatos.\nNao tenha medo de negociar Profissionais pleno frequentemente aceitam a primeira proposta sem negociar. Pesquise o mercado, conheça seu valor e apresente argumentos solidos durante a negociacao. Muitas empresas tem margem para ajustar a oferta em 10 a 20 por cento.\nConsidere beneficios além do salário Stock options, bnus por performance, orcamento para educacao, horario flexivel e dias de folga adicionais são beneficios que podem fazer uma diferenca significativa na sua qualidade de vida e crescimento profissional.\nInvista em soft skills Profissionais que se comunicam bem, colaboram de forma eficiente e demonstram lideranca técnica são promovidos mais rapidamente e recebem propostas melhores do mercado.\nPerspectivas de crescimento A transicao de pleno para senior costuma levar entre dois e quatro anos para profissionais dedicados. Nesse proximo nível, os salários podem chegar a R$ 20.000 ou mais no regime CLT. Alem da trilha técnica, o nível pleno é o momento ideal para avaliar se você deseja seguir como especialista técnico, migrar para gestao de equipes ou explorar carreiras como arquiteto de software.\nConclusão O desenvolvedor Kotlin pleno no Brasil em 2026 conta com um mercado aquecido e remuneracao atrativa. Com salários que variam de R$ 6.500 a R$ 16.000 dependendo do regime e da localização, a carreira oferece estabilidade e perspectivas solidas de crescimento. A chave para alcancar as melhores faixas salariais esta na combinacao de excelencia técnica, habilidades comportamentais e posicionamento estrategico no mercado. Compare também com salários de desenvolvedores Go e Python, que competem no mesmo mercado de backend e serviços.\n","permalink":"https://kotlin.dev.br/carreira/salario-dev-kotlin-pleno/","summary":"\u003ch2 id=\"quanto-ganha-um-desenvolvedor-kotlin-pleno-em-2026\"\u003eQuanto ganha um desenvolvedor Kotlin pleno em 2026?\u003c/h2\u003e\n\u003cp\u003eO nível pleno representa uma fase crucial na carreira de um desenvolvedor Kotlin. E nesse estagio que o profissional consolida seus conhecimentos tecnicos, assume responsabilidades maiores em projetos e experimenta um salto significativo na remuneracao. Se você já tem entre dois e cinco anos de experiência com Kotlin e quer entender como esta o mercado, este artigo traz todas as informações que você precisa sobre salários, habilidades e oportunidades em 2026.\u003c/p\u003e","title":"Salário de Desenvolvedor Kotlin Pleno: Quanto Ganha em 2026 | Kotlin Brasil"},{"content":"Kotlin vs Java em 2026: a comparação definitiva A comparação entre Kotlin e Java é uma das mais relevantes no ecossistema JVM. Ambas as linguagens coexistem na mesma plataforma e compartilham interoperabilidade total, mas diferem significativamente em filosofia, sintaxe e funcionalidades. Este artigo apresenta uma análise aprofundada para ajudar você a decidir qual linguagem utilizar em seus projetos em 2026.\nVisao geral Kotlin foi criado pela JetBrains em 2011 e lancado oficialmente em 2016. Foi projetado como uma alternativa moderna ao Java, eliminando verbosidade e adicionando funcionalidades que aumentam a produtividade. Java, criado pela Sun Microsystems em 1995, é uma das linguagens mais utilizadas no mundo, com um ecossistema maduro é uma base de código gigantesca.\nCaracteristica Kotlin Java Ano de lancamento 2016 1995 Criador JetBrains Sun Microsystems (Oracle) Tipagem Estática com inferencia Estática Null safety Nativo no sistema de tipos Opcional via anotações Paradigma OO + Funcional OO (funcional parcial) Plataformas JVM, Android, Nativo, JS, WASM JVM IDE principal IntelliJ IDEA IntelliJ IDEA / Eclipse Sintaxe e produtividade Uma das diferenças mais evidentes entre as linguagens esta na quantidade de código necessária para realizar a mesma tarefa.\nDeclaracao de uma classe de dados em Kotlin:\ndata class Usuario( val nome: String, val email: String, val idade: Int ) Equivalente em Java (antes dos Records):\npublic class Usuario { private final String nome; private final String email; private final int idade; public Usuario(String nome, String email, int idade) { this.nome = nome; this.email = email; this.idade = idade; } public String getNome() { return nome; } public String getEmail() { return email; } public int getIdade() { return idade; } @Override public boolean equals(Object o) { /* implementacao */ } @Override public int hashCode() { /* implementacao */ } @Override public String toString() { /* implementacao */ } } Com Java Records, introduzidos no Java 16, a verbosidade foi reduzida:\npublic record Usuario(String nome, String email, int idade) {} No entanto, Records são imutáveis e possuem limitações que data classes de Kotlin não tem, como a impossibilidade de heranca e a ausência do método copy.\nNull safety O sistema de null safety de Kotlin e uma das suas maiores vantagens sobre Java. Em Kotlin, o compilador distingue entre tipos nulaveis e não nulaveis:\nvar nome: String = \u0026#34;Kotlin\u0026#34; // nao pode ser null var apelido: String? = null // pode ser null // Acesso seguro val tamanho = apelido?.length ?: 0 Em Java, qualquer referência pode ser null, e NullPointerException e um dos erros mais comuns:\nString nome = \u0026#34;Java\u0026#34;; String apelido = null; // Pode lancar NullPointerException int tamanho = apelido.length(); // RuntimeException! Java possui anotações como @Nullable e @NotNull, mas elas são opcionais e não enforced pelo compilador.\nCoroutines versus threads Kotlin oferece coroutines como mecanismo nativo para programação assíncrona:\nsuspend fun buscarDados(): List\u0026lt;Usuario\u0026gt; { val usuarios = withContext(Dispatchers.IO) { api.buscarUsuarios() } return usuarios } Java utiliza threads, CompletableFuture ou, mais recentemente, virtual threads do Project Loom:\nCompletableFuture\u0026lt;List\u0026lt;Usuario\u0026gt;\u0026gt; buscarDados() { return CompletableFuture.supplyAsync(() -\u0026gt; { return api.buscarUsuarios(); }); } Coroutines são mais leves que threads tradicionais e oferecem uma sintaxe mais intuitiva para código assíncrono. Virtual threads do Java aproximam a experiência, mas coroutines de Kotlin ainda oferecem mais controle e integração com a linguagem.\nPerformance Em termos de performance de runtime, Kotlin e Java são praticamente identicos. Ambos compilam para bytecode JVM e rodam na mesma maquina virtual. A diferenca de performance entre as linguagens e negligivel na grande maioria dos casos.\nAspecto Kotlin Java Performance de runtime Equivalente Equivalente Tempo de compilação Ligeiramente mais lento Mais rápido Uso de memória Equivalente Equivalente Startup time Equivalente Equivalente Inline functions Sim (zero overhead) Nao O tempo de compilação de Kotlin e ligeiramente superior ao de Java, mas a diferenca diminui a cada versão do compilador e e compensada pela reducao no tempo de escrita de código.\nEcossistema e bibliotecas Java possui o maior ecossistema de bibliotecas e frameworks do mundo. Spring Framework, Hibernate, Apache libraries e milhares de outras são referência na industria. Kotlin pode utilizar todas essas bibliotecas sem modificacao, gracas a interoperabilidade total.\nAlem disso, Kotlin possui seu próprio ecossistema crescente com bibliotecas como Ktor para servidor web, Exposed para banco de dados, Kotlinx Serialization para serialização e kotlinx.coroutines para programação assíncrona.\nMercado de trabalho No mercado brasileiro, Java ainda possui mais vagas em volume absoluto, especialmente em sistemas legados e corporacoes tradicionais. Porem, Kotlin domina as novas contratacoes em Android e cresce rapidamente no backend, especialmente em fintechs e startups.\nProfissionais que dominam ambas as linguagens tem vantagem competitiva, pois podem trabalhar em projetos legados Java e novos projetos Kotlin com igual fluencia.\nCasos de uso recomendados Quando usar Kotlin Escolha Kotlin para novos projetos Android, novos serviços backend que priorizam produtividade, projetos que se beneficiam de null safety, aplicações multiplataforma com Kotlin Multiplatform e equipes que valorizam código conciso e expressivo.\nQuando usar Java Java pode ser preferivel em projetos legados com grande base de código Java existente, equipes com forte expertise em Java sem disponibilidade para treinamento, projetos que dependem de frameworks que ainda não suportam Kotlin nativamente e ambientes corporativos com politicas de tecnologia conservadoras.\nVeredicto Em 2026, Kotlin e a escolha superior para novos projetos na JVM. A produtividade, null safety, coroutines e a sintaxe moderna justificam a adoção em praticamente todos os cenários. Java permanece relevante por seu ecossistema massivo e base instalada, mas a tendencia de mercado aponta claramente para uma adoção crescente de Kotlin. Para novos desenvolvedores, aprender Kotlin como primeira linguagem JVM e a recomendacao mais acertada. Para desenvolvedores Java experientes, a transicao para Kotlin e um investimento de carreira com retorno garantido. Se você está avaliando outras linguagens além da JVM, confira nossas análises sobre Go para backend e Rust para sistemas de alta performance.\n","permalink":"https://kotlin.dev.br/comparacoes/kotlin-vs-java-2026/","summary":"\u003ch2 id=\"kotlin-vs-java-em-2026-a-comparação-definitiva\"\u003eKotlin vs Java em 2026: a comparação definitiva\u003c/h2\u003e\n\u003cp\u003eA comparação entre Kotlin e Java é uma das mais relevantes no ecossistema JVM. Ambas as linguagens coexistem na mesma plataforma e compartilham interoperabilidade total, mas diferem significativamente em filosofia, sintaxe e funcionalidades. Este artigo apresenta uma análise aprofundada para ajudar você a decidir qual linguagem utilizar em seus projetos em 2026.\u003c/p\u003e\n\u003ch2 id=\"visao-geral\"\u003eVisao geral\u003c/h2\u003e\n\u003cp\u003eKotlin foi criado pela JetBrains em 2011 e lancado oficialmente em 2016. Foi projetado como uma alternativa moderna ao Java, eliminando verbosidade e adicionando funcionalidades que aumentam a produtividade. Java, criado pela Sun Microsystems em 1995, é uma das linguagens mais utilizadas no mundo, com um ecossistema maduro é uma base de código gigantesca.\u003c/p\u003e","title":"Kotlin vs Java: Qual Melhor em 2026? | Kotlin Brasil"},{"content":"Quanto ganha um desenvolvedor Kotlin júnior em 2026? Um desenvolvedor Kotlin júnior no Brasil ganha, em média, entre R$ 3.500 e R$ 6.500 por mês em regime CLT. Em vagas PJ, a faixa costuma ficar entre R$ 5.000 e R$ 8.500, porque a empresa transfere para o profissional custos como férias, 13º, plano de saúde, contador e reserva financeira.\nEsses números variam bastante conforme cidade, tipo de empresa, stack e maturidade técnica. Um júnior que só conhece sintaxe básica tende a entrar na parte baixa da faixa. Já alguém que consegue entregar uma tela Android com Jetpack Compose, consumir API com Retrofit, escrever testes simples e explicar coroutines entra na disputa por propostas melhores.\nO ponto mais importante: Kotlin júnior não é uma carreira separada de Android ou backend. No Brasil, a maioria das vagas júnior aparece em três caminhos:\nAndroid com Kotlin, Compose, Room, Retrofit e arquitetura MVVM. Backend Kotlin com Spring Boot, Ktor, APIs REST e bancos SQL. Times Java que estão migrando partes do produto para Kotlin. Se você está começando, use esta página como referência prática de remuneração e compare com o guia completo de salários Kotlin no Brasil para entender a progressão até pleno, sênior e remoto internacional.\nTabela de salário Kotlin júnior no Brasil Regime Faixa mensal em 2026 Média prática Quando faz sentido CLT júnior inicial R$ 3.500 a R$ 4.500 R$ 4.000 Primeiro emprego, estágio efetivado ou transição de carreira CLT júnior forte R$ 4.500 a R$ 6.500 R$ 5.500 Já tem projetos, base Android/backend e alguma experiência real PJ júnior R$ 5.000 a R$ 8.500 R$ 6.500 Contratos com menos benefícios e mais responsabilidade financeira Remoto para empresa brasileira R$ 4.500 a R$ 7.500 R$ 6.000 Empresa de capital ou startup contratando fora do eixo local Para comparar CLT e PJ, não olhe só o valor bruto. Um CLT de R$ 5.500 com benefícios pode ser melhor que um PJ de R$ 6.500 sem plano de saúde, sem férias remuneradas e sem previsibilidade. Como júnior, segurança, mentoria e feedback frequente costumam valer muito no primeiro salto de carreira.\nVariação por região A localização ainda pesa, mesmo com o avanço do trabalho remoto. Empresas de São Paulo e grandes polos tendem a pagar mais, principalmente quando a vaga envolve produto digital, fintech, banco, marketplace ou consultoria enterprise.\nRegião Faixa CLT júnior Observação São Paulo e Campinas R$ 4.500 a R$ 6.500 Maior concentração de fintechs, bancos, consultorias e startups Rio de Janeiro e Belo Horizonte R$ 4.000 a R$ 5.800 Bom volume de vagas híbridas e consultorias Curitiba, Florianópolis e Porto Alegre R$ 3.800 a R$ 5.800 Ecossistema forte de produto, mobile e software houses Recife, Salvador e Fortaleza R$ 3.500 a R$ 5.000 Cenas tech em crescimento, com destaque para Recife Brasília e Centro-Oeste R$ 3.800 a R$ 5.500 Consultorias, governo, bancos e sistemas corporativos Vagas remotas mudam essa conta. Um dev em uma cidade menor pode receber faixa de capital se competir bem tecnicamente. Por isso, além de estudar Kotlin, vale investir cedo em portfólio, comunicação escrita e inglês técnico.\nO que uma vaga Kotlin júnior realmente cobra? Vaga júnior não deveria exigir arquitetura complexa, liderança técnica ou domínio completo de produção. Mesmo assim, o mercado brasileiro costuma misturar requisitos de júnior e pleno. Para filtrar melhor, procure anúncios em que o escopo principal seja aprender com o time e entregar tarefas bem delimitadas.\nBase obrigatória da linguagem Você precisa dominar os fundamentos que aparecem em qualquer entrevista:\nval e var, tipos básicos, funções e classes. Null safety e uso correto de ?, ?: e let. data class, sealed class, enums e objetos. Coleções, map, filter, groupBy e imutabilidade. Extension functions e funções de escopo. Leitura de código Java, porque muitos projetos Kotlin convivem com Java. Se esses pontos ainda parecem instáveis, comece pelo guia completo de Kotlin e pratique com projetos pequenos antes de aplicar para vagas mais exigentes.\nPara Android júnior No caminho Android, as habilidades que mais aparecem são:\nAndroid Studio, Gradle e ciclo de build. Activity, ViewModel, estado de tela e navegação. Jetpack Compose para interfaces modernas. Retrofit ou Ktor Client para consumir APIs. Room ou DataStore para persistência local. Testes unitários simples e noções de arquitetura MVVM. Um portfólio com dois apps bem acabados costuma pesar mais que vários certificados soltos. O ideal é ter um app que consome API real, um app com persistência local e pelo menos um README explicando decisões técnicas.\nPara backend Kotlin júnior No backend, as empresas buscam alguém que entenda HTTP, banco de dados e organização de código. Os requisitos comuns são:\nCriar APIs REST com Spring Boot ou Ktor. Modelar DTOs, entidades e validações. Conectar com PostgreSQL, MySQL ou outro banco relacional. Usar Git, pull request e pipeline básico de CI. Escrever testes com JUnit, MockK ou Kotest. Entender autenticação, logs e tratamento de erro. Se você quer esse caminho, leia também Kotlin para backend e Kotlin com Spring Boot. Backend Kotlin ainda tem menos vagas júnior que Android, mas pode pagar bem quando a empresa já usa JVM em produção.\nComo aumentar o salário ainda no nível júnior O primeiro aumento não vem de decorar mais sintaxe. Ele vem de reduzir o risco percebido por quem contrata. Um júnior melhor remunerado passa a impressão de que aprende rápido, entrega com cuidado e não precisa ser guiado em cada linha.\n1. Construa um portfólio que pareça trabalho real Evite só projetos de tutorial. Um bom portfólio Kotlin júnior tem:\nREADME claro, com prints, decisões e como rodar. Código organizado em camadas simples. Tratamento de erro e estados de carregamento. Testes em pelo menos partes críticas. Commits legíveis e histórico que mostre evolução. Veja o guia de portfólio para desenvolvedor Kotlin para transformar estudos em prova concreta de capacidade.\n2. Escolha uma especialização inicial No começo, tentar estudar Android, backend, multiplatform, dados e DevOps ao mesmo tempo dilui energia. Escolha um eixo para a primeira vaga:\nAndroid se você gosta de produto, interface e apps móveis. Backend se você prefere APIs, bancos, integração e arquitetura. Kotlin Multiplatform se você já tem base mobile e quer um diferencial mais raro. Depois do primeiro emprego, fica mais fácil expandir. Para planejar o caminho, compare os roadmaps de dev Android e backend Kotlin.\n3. Treine entrevista técnica com exemplos pequenos Muitas entrevistas júnior não cobram algoritmos pesados, mas cobram raciocínio. Pratique explicar por que usaria data class, quando uma variável pode ser nula, como tratar erro de API e como quebrar uma tela em estados.\nTambém treine leitura de código. Em vagas Kotlin, é comum receber um trecho com suspend, Flow, nullable types ou classes Java e precisar explicar o comportamento. O guia de coroutines avançadas ajuda quando você já passou do básico.\n4. Use vagas como mapa de estudo Mesmo antes de aplicar, leia anúncios em vagas Kotlin e marque requisitos recorrentes. Se cinco vagas pedem Compose, ele entra no plano. Se três pedem Spring Boot, faça uma API pequena. Se uma vaga exige dez tecnologias sem mentoria, talvez ela não seja júnior de verdade.\nEssa leitura evita estudar no escuro. O objetivo não é virar especialista antes da primeira vaga, mas ficar forte no conjunto que o mercado já está sinalizando.\nCLT ou PJ para júnior: qual vale mais? Para a maioria dos iniciantes, CLT é melhor no primeiro emprego. O salário bruto pode ser menor, mas o pacote inclui férias, 13º, FGTS, benefícios e mais proteção. Também é mais comum que empresas CLT tenham onboarding, pareamento, plano de carreira e feedback estruturado.\nPJ pode valer a pena quando:\nO valor bruto compensa de verdade a perda de benefícios. Você já tem reserva financeira. O contrato tem escopo claro e previsibilidade. Existe mentoria técnica, não só cobrança por entrega. Se a diferença entre CLT e PJ for pequena, escolha o ambiente que acelera aprendizado. O primeiro ano de carreira vale mais pela base construída do que por algumas centenas de reais a mais.\nPerguntas rápidas sobre salário Kotlin júnior Kotlin júnior ganha mais que Java júnior? Em muitas empresas, as faixas são parecidas porque Kotlin roda no ecossistema JVM e convive com Java. A vantagem de Kotlin aparece quando a vaga é Android moderna, Kotlin Multiplatform ou backend com stack Kotlin-first. Nesses casos, a oferta menor de profissionais pode melhorar a negociação.\nDá para conseguir vaga Kotlin júnior sem faculdade? Dá, mas você precisa compensar com portfólio, projetos reais, boa comunicação e base técnica consistente. Faculdade ainda ajuda em estágios e grandes empresas, mas não é o único caminho. Para quem está começando do zero, projetos publicados e prática constante contam muito.\nQuanto tempo leva para sair de júnior para pleno? Em média, de dois a quatro anos. Quem pega bons projetos, recebe mentoria, escreve testes, participa de decisões e estuda com foco pode acelerar. Quem fica só em tarefas repetitivas demora mais, mesmo com o mesmo tempo de carteira.\nQual especialização paga melhor no começo? Android com Compose costuma abrir mais portas júnior. Backend Kotlin pode pagar bem, mas normalmente exige base maior de HTTP, banco, testes e deploy. Kotlin Multiplatform é promissor, mas ainda aparece mais em vagas pleno/sênior.\nProgressão de salário por senioridade e área O salário júnior é só o ponto de partida. Para entender a evolução completa da carreira Kotlin, acompanhe as faixas dos próximos níveis e das especializações que costumam pagar mais:\nSalário Kotlin Pleno — a faixa mais disputada do mercado, onde a maioria dos desenvolvedores passa mais tempo. Salário Kotlin Sênior — inclui vagas remotas internacionais com remuneração em dólar. Salário Android Kotlin — o maior volume de vagas Kotlin no Brasil. Salário Backend Kotlin — Spring Boot e Ktor, com foco em APIs e JVM. Salários Kotlin no Brasil (visão geral) — o mapa completo de júnior a especialista e staff. Comparar os níveis ajuda a planejar o próximo salto e a entender o que diferencia uma faixa da outra em regime CLT, PJ e remoto.\nPróximos passos Se você está mirando a primeira vaga, foque em um plano simples:\nRevise os fundamentos com o guia completo de Kotlin. Escolha Android ou backend como trilha inicial. Monte dois projetos de portfólio bem documentados. Acompanhe vagas Kotlin no Brasil semanalmente. Compare sua evolução com a página de salários Kotlin por senioridade. O salário de um desenvolvedor Kotlin júnior em 2026 varia bastante, mas a direção é clara: quem combina fundamentos sólidos, projetos públicos, alguma especialização e capacidade de aprender em equipe chega mais rápido às melhores faixas. Compare também os salários iniciais em outras linguagens populares: Python, Go e Rust.\n","permalink":"https://kotlin.dev.br/carreira/salario-dev-kotlin-junior/","summary":"\u003ch2 id=\"quanto-ganha-um-desenvolvedor-kotlin-júnior-em-2026\"\u003eQuanto ganha um desenvolvedor Kotlin júnior em 2026?\u003c/h2\u003e\n\u003cp\u003eUm \u003cstrong\u003edesenvolvedor Kotlin júnior no Brasil ganha, em média, entre R$ 3.500 e R$ 6.500 por mês em regime CLT\u003c/strong\u003e. Em vagas PJ, a faixa costuma ficar entre \u003cstrong\u003eR$ 5.000 e R$ 8.500\u003c/strong\u003e, porque a empresa transfere para o profissional custos como férias, 13º, plano de saúde, contador e reserva financeira.\u003c/p\u003e\n\u003cp\u003eEsses números variam bastante conforme cidade, tipo de empresa, stack e maturidade técnica. Um júnior que só conhece sintaxe básica tende a entrar na parte baixa da faixa. Já alguém que consegue entregar uma tela Android com \u003ca href=\"/guias/guia-jetpack-compose/\"\u003eJetpack Compose\u003c/a\u003e, consumir API com Retrofit, escrever testes simples e explicar \u003ca href=\"/blog/coroutines-kotlin/\"\u003ecoroutines\u003c/a\u003e entra na disputa por propostas melhores.\u003c/p\u003e","title":"Salário Desenvolvedor Kotlin Júnior 2026: CLT, PJ e Remoto"},{"content":"AWS Lambda é o serviço serverless mais usado no mundo, e Kotlin é uma escolha excelente para criar funções Lambda robustas e performaticas. Neste artigo, vamos explorar como desenvolver, otimizar e fazer deploy de funções Lambda com Kotlin.\nPor Que Kotlin no AWS Lambda Kotlin traz vantagens significativas para desenvolvimento serverless:\nNull safety: Reduz erros em runtime, criticos em ambientes serverless onde debugging é mais difícil Concisao: Menos código significa menos bugs e deploy mais rápido Ecossistema JVM: Acesso a todas as bibliotecas Java, incluindo o AWS SDK Coroutines: Gerenciamento eficiente de operações assíncronas O principal desafio histórico de usar JVM no Lambda era o cold start. Com otimizações recentes (SnapStart, GraalVM, Kotlin/Native), esse problema esta cada vez menor. Linguagens como Go e Rust têm cold start praticamente zero, mas Kotlin compensa com o ecossistema JVM e produtividade do desenvolvedor.\nPrimeira Função Lambda com Kotlin Setup do Projeto // build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.1.0\u0026#34; kotlin(\u0026#34;plugin.serialization\u0026#34;) version \u0026#34;2.1.0\u0026#34; id(\u0026#34;com.github.johnrengelman.shadow\u0026#34;) version \u0026#34;8.1.1\u0026#34; // Fat JAR } dependencies { implementation(\u0026#34;com.amazonaws:aws-lambda-java-core:1.2.3\u0026#34;) implementation(\u0026#34;com.amazonaws:aws-lambda-java-events:3.11.4\u0026#34;) implementation(\u0026#34;software.amazon.awssdk:dynamodb:2.25.0\u0026#34;) implementation(\u0026#34;software.amazon.awssdk:s3:2.25.0\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0\u0026#34;) testImplementation(kotlin(\u0026#34;test\u0026#34;)) testImplementation(\u0026#34;io.mockk:mockk:1.13.9\u0026#34;) } tasks.shadowJar { archiveClassifier.set(\u0026#34;\u0026#34;) mergeServiceFiles() } Handler Básico // Handler para API Gateway class ProdutoHandler : RequestHandler\u0026lt;APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent\u0026gt; { private val produtoService = ProdutoService() private val json = Json { ignoreUnknownKeys = true encodeDefaults = true } override fun handleRequest( input: APIGatewayProxyRequestEvent, context: Context ): APIGatewayProxyResponseEvent { context.logger.log(\u0026#34;Recebida requisicao: ${input.httpMethod} ${input.path}\u0026#34;) return try { when (input.httpMethod) { \u0026#34;GET\u0026#34; -\u0026gt; handleGet(input) \u0026#34;POST\u0026#34; -\u0026gt; handlePost(input) else -\u0026gt; response(405, mapOf(\u0026#34;error\u0026#34; to \u0026#34;Metodo nao permitido\u0026#34;)) } } catch (e: Exception) { context.logger.log(\u0026#34;Erro: ${e.message}\u0026#34;) response(500, mapOf(\u0026#34;error\u0026#34; to \u0026#34;Erro interno\u0026#34;)) } } private fun handleGet(input: APIGatewayProxyRequestEvent): APIGatewayProxyResponseEvent { val id = input.pathParameters?.get(\u0026#34;id\u0026#34;) return if (id != null) { val produto = produtoService.buscarPorId(id) if (produto != null) { response(200, produto) } else { response(404, mapOf(\u0026#34;error\u0026#34; to \u0026#34;Produto nao encontrado\u0026#34;)) } } else { val produtos = produtoService.listarTodos() response(200, produtos) } } private fun handlePost(input: APIGatewayProxyRequestEvent): APIGatewayProxyResponseEvent { val request = json.decodeFromString\u0026lt;CriarProdutoRequest\u0026gt;(input.body) val produto = produtoService.criar(request) return response(201, produto) } private fun \u0026lt;T\u0026gt; response(statusCode: Int, body: T): APIGatewayProxyResponseEvent { return APIGatewayProxyResponseEvent().apply { this.statusCode = statusCode this.headers = mapOf( \u0026#34;Content-Type\u0026#34; to \u0026#34;application/json\u0026#34;, \u0026#34;Access-Control-Allow-Origin\u0026#34; to \u0026#34;*\u0026#34; ) this.body = json.encodeToString( serializer = kotlinx.serialization.serializer(), value = body ) } } } Integração com DynamoDB DynamoDB e o banco de dados mais usado com Lambda:\n// Service para DynamoDB com Kotlin class ProdutoService { private val dynamoDb = DynamoDbClient.builder() .region(Region.SA_EAST_1) .build() private val tableName = System.getenv(\u0026#34;PRODUTOS_TABLE\u0026#34;) ?: \u0026#34;produtos\u0026#34; private val json = Json { ignoreUnknownKeys = true } fun buscarPorId(id: String): Produto? { val request = GetItemRequest.builder() .tableName(tableName) .key(mapOf(\u0026#34;id\u0026#34; to AttributeValue.builder().s(id).build())) .build() val response = dynamoDb.getItem(request) return if (response.hasItem()) { response.item().toProduto() } else null } fun criar(request: CriarProdutoRequest): Produto { val produto = Produto( id = java.util.UUID.randomUUID().toString(), nome = request.nome, preco = request.preco, categoria = request.categoria, criadoEm = java.time.Instant.now().toString() ) val item = mapOf( \u0026#34;id\u0026#34; to AttributeValue.builder().s(produto.id).build(), \u0026#34;nome\u0026#34; to AttributeValue.builder().s(produto.nome).build(), \u0026#34;preco\u0026#34; to AttributeValue.builder().n(produto.preco.toString()).build(), \u0026#34;categoria\u0026#34; to AttributeValue.builder().s(produto.categoria).build(), \u0026#34;criadoEm\u0026#34; to AttributeValue.builder().s(produto.criadoEm).build() ) dynamoDb.putItem( PutItemRequest.builder() .tableName(tableName) .item(item) .build() ) return produto } fun listarTodos(): List\u0026lt;Produto\u0026gt; { val response = dynamoDb.scan( ScanRequest.builder() .tableName(tableName) .limit(100) .build() ) return response.items().map { it.toProduto() } } private fun Map\u0026lt;String, AttributeValue\u0026gt;.toProduto(): Produto { return Produto( id = this[\u0026#34;id\u0026#34;]!!.s(), nome = this[\u0026#34;nome\u0026#34;]!!.s(), preco = this[\u0026#34;preco\u0026#34;]!!.n().toDouble(), categoria = this[\u0026#34;categoria\u0026#34;]!!.s(), criadoEm = this[\u0026#34;criadoEm\u0026#34;]!!.s() ) } } @Serializable data class Produto( val id: String, val nome: String, val preco: Double, val categoria: String, val criadoEm: String ) @Serializable data class CriarProdutoRequest( val nome: String, val preco: Double, val categoria: String ) Otimizando Cold Start O cold start e o maior desafio de JVM no Lambda — linguagens como Go e Rust possuem cold start quase zero em funções serverless, mas Kotlin compensa com expressividade e ecossistema. Aqui estao estrategias para minimiza-lo:\nAWS SnapStart SnapStart cria um snapshot da JVM apos a inicialização, eliminando o cold start em invocacoes subsequentes:\n// Para usar SnapStart, adicione ao template SAM: // Properties: // SnapStart: // ApplyOn: PublishedVersions // Otimize o codigo para SnapStart class OptimizedHandler : RequestHandler\u0026lt;APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent\u0026gt; { // Inicialize clientes no companion object (cached entre invocacoes) companion object { private val dynamoDb = DynamoDbClient.builder() .region(Region.SA_EAST_1) .httpClientBuilder(UrlConnectionHttpClient.builder()) .build() private val json = Json { ignoreUnknownKeys = true encodeDefaults = true } } override fun handleRequest( input: APIGatewayProxyRequestEvent, context: Context ): APIGatewayProxyResponseEvent { // Handler logic usando clientes pre-inicializados return processarRequisicao(input, context) } private fun processarRequisicao( input: APIGatewayProxyRequestEvent, context: Context ): APIGatewayProxyResponseEvent { // ...processar return APIGatewayProxyResponseEvent().apply { statusCode = 200 body = \u0026#34;{\\\u0026#34;status\\\u0026#34;: \\\u0026#34;ok\\\u0026#34;}\u0026#34; } } } Reducao de Dependências Cada dependência adiciona tempo ao cold start:\n// Use apenas o que precisa do AWS SDK v2 dependencies { // Em vez de importar o SDK inteiro: // implementation(\u0026#34;software.amazon.awssdk:aws-sdk-java:2.25.0\u0026#34;) // NAO! // Importe apenas os modulos necessarios: implementation(\u0026#34;software.amazon.awssdk:dynamodb:2.25.0\u0026#34;) implementation(\u0026#34;software.amazon.awssdk:url-connection-client:2.25.0\u0026#34;) // HTTP client leve } Configuração de Memória Mais memória no Lambda significa mais CPU, o que acelera o cold start:\n// Regra pratica para Kotlin Lambda: // - Minimo 512MB para funcoes simples // - 1024MB para funcoes com mais dependências // - 2048MB+ para funcoes com muitas dependências ou processamento pesado // A relação custo-beneficio costuma ser otima com 1024MB // Funções rodam mais rapido e o custo total pode ser MENOR Processamento de Eventos Lambda não e apenas para APIs. Processar eventos e um caso de uso poderoso:\n// Processador de eventos SQS class SqsEventHandler : RequestHandler\u0026lt;SQSEvent, Void?\u0026gt; { private val pedidoProcessor = PedidoProcessor() override fun handleRequest(event: SQSEvent, context: Context): Void? { val logger = context.logger event.records.forEach { record -\u0026gt; try { logger.log(\u0026#34;Processando mensagem: ${record.messageId}\u0026#34;) val pedido = Json.decodeFromString\u0026lt;PedidoEvento\u0026gt;(record.body) pedidoProcessor.processar(pedido) logger.log(\u0026#34;Mensagem processada com sucesso: ${record.messageId}\u0026#34;) } catch (e: Exception) { logger.log(\u0026#34;Erro ao processar mensagem ${record.messageId}: ${e.message}\u0026#34;) throw e // Re-throw para SQS retry } } return null } } // Processador de eventos S3 class S3EventHandler : RequestHandler\u0026lt;S3Event, String\u0026gt; { override fun handleRequest(event: S3Event, context: Context): String { val record = event.records.first() val bucket = record.s3.bucket.name val key = record.s3.`object`.key context.logger.log(\u0026#34;Novo arquivo: s3://$bucket/$key\u0026#34;) // Processar arquivo val s3Client = S3Client.builder().region(Region.SA_EAST_1).build() val response = s3Client.getObject( GetObjectRequest.builder() .bucket(bucket) .key(key) .build() ) val conteudo = response.readAllBytes().decodeToString() // Processar conteudo... return \u0026#34;Processado: $key\u0026#34; } } Testes Locais Testar Lambda localmente acelera o desenvolvimento:\n// Testes unitarios para Lambda handlers class ProdutoHandlerTest { private val handler = ProdutoHandler() @Test fun `deve retornar produto quando existe`() { val event = APIGatewayProxyRequestEvent().apply { httpMethod = \u0026#34;GET\u0026#34; pathParameters = mapOf(\u0026#34;id\u0026#34; to \u0026#34;prod-123\u0026#34;) } val context = mockk\u0026lt;Context\u0026gt; { every { logger } returns mockk(relaxed = true) } val response = handler.handleRequest(event, context) assertEquals(200, response.statusCode) assertTrue(response.body.contains(\u0026#34;prod-123\u0026#34;)) } @Test fun `deve retornar 404 quando produto nao existe`() { val event = APIGatewayProxyRequestEvent().apply { httpMethod = \u0026#34;GET\u0026#34; pathParameters = mapOf(\u0026#34;id\u0026#34; to \u0026#34;inexistente\u0026#34;) } val context = mockk\u0026lt;Context\u0026gt; { every { logger } returns mockk(relaxed = true) } val response = handler.handleRequest(event, context) assertEquals(404, response.statusCode) } } Conclusão Kotlin no AWS Lambda e uma combinacao madura e pronta para producao. Com as otimizações certas, especialmente SnapStart e gerenciamento cuidadoso de dependências, o cold start deixa de ser um problema significativo. A combinacao de null safety, coroutines e o ecossistema JVM torna Kotlin uma das melhores linguagens para desenvolvimento serverless robusto.\nComece com funções simples, otimize gradualmente e aproveite todo o poder do ecossistema Kotlin no mundo serverless. Se o cold start for crítico para seu caso de uso, Python é a linguagem mais popular no Lambda, enquanto Rust oferece a melhor performance bruta. Com a AWS expandindo constantemente o suporte a JVM, o futuro do Kotlin no Lambda e promissor.\n","permalink":"https://kotlin.dev.br/blog/kotlin-aws-lambda/","summary":"\u003cp\u003eAWS Lambda é o serviço serverless mais usado no mundo, e Kotlin é uma escolha excelente para criar funções Lambda robustas e performaticas. Neste artigo, vamos explorar como desenvolver, otimizar e fazer deploy de funções Lambda com Kotlin.\u003c/p\u003e\n\u003ch2 id=\"por-que-kotlin-no-aws-lambda\"\u003ePor Que Kotlin no AWS Lambda\u003c/h2\u003e\n\u003cp\u003eKotlin traz vantagens significativas para desenvolvimento serverless:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eNull safety:\u003c/strong\u003e Reduz erros em runtime, criticos em ambientes serverless onde debugging é mais difícil\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eConcisao:\u003c/strong\u003e Menos código significa menos bugs e deploy mais rápido\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eEcossistema JVM:\u003c/strong\u003e Acesso a todas as bibliotecas Java, incluindo o AWS SDK\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCoroutines:\u003c/strong\u003e Gerenciamento eficiente de operações assíncronas\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eO principal desafio histórico de usar JVM no Lambda era o cold start. Com otimizações recentes (SnapStart, GraalVM, Kotlin/Native), esse problema esta cada vez menor. Linguagens como \u003ca href=\"https://golang.com.br/\" target=\"_blank\" rel=\"noopener\" onclick=\"umami.track('portfolio-site-click', { destination: 'golang.com.br' })\"\u003eGo\u003c/a\u003e e \u003ca href=\"https://rustlang.com.br/\" target=\"_blank\" rel=\"noopener\" onclick=\"umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })\"\u003eRust\u003c/a\u003e têm cold start praticamente zero, mas Kotlin compensa com o ecossistema JVM e produtividade do desenvolvedor.\u003c/p\u003e","title":"Kotlin com AWS Lambda: Serverless na JVM | Kotlin Brasil"},{"content":"Kubernetes — que é escrito em Go — se consolidou como o padrão para orquestracao de containers, e aplicações Kotlin rodam excepcionalmente bem nesse ambiente. Com a JVM otimizada para containers e frameworks como Spring Boot e Ktor prontos para cloud-native, Kotlin e Kubernetes formam uma dupla poderosa. Vamos explorar como fazer isso na prática.\nPreparando a Aplicação Kotlin para Kubernetes Dockerfile Otimizado O primeiro passo e criar uma imagem Docker eficiente:\n// build.gradle.kts - Configuração para gerar JAR otimizado plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.1.0\u0026#34; kotlin(\u0026#34;plugin.spring\u0026#34;) version \u0026#34;2.1.0\u0026#34; id(\u0026#34;org.springframework.boot\u0026#34;) version \u0026#34;3.3.0\u0026#34; id(\u0026#34;io.spring.dependency-management\u0026#34;) version \u0026#34;1.1.4\u0026#34; } tasks.bootJar { archiveFileName.set(\u0026#34;app.jar\u0026#34;) layerTools { enabled = true // Habilita layer tools para build Docker eficiente } } // Configurações JVM para containers tasks.bootRun { jvmArgs = listOf( \u0026#34;-XX:+UseContainerSupport\u0026#34;, \u0026#34;-XX:MaxRAMPercentage=75.0\u0026#34;, \u0026#34;-XX:InitialRAMPercentage=50.0\u0026#34; ) } O Dockerfile multi-stage ideal para Spring Boot com Kotlin usa layer extraction para maximizar cache de camadas Docker. A primeira fase extrai as camadas do JAR, e a segunda fase copia cada camada separadamente, permitindo que o Docker reutilize cache para camadas que não mudaram.\nHealth Checks para Kubernetes Kubernetes usa probes para gerenciar o ciclo de vida dos pods:\n// Health checks detalhados para Kubernetes @RestController class KubernetesHealthController( private val dataSource: DataSource ) { // Liveness probe - \u0026#34;A aplicacao esta viva?\u0026#34; // Se falhar, Kubernetes reinicia o pod @GetMapping(\u0026#34;/health/live\u0026#34;) fun liveness(): ResponseEntity\u0026lt;Map\u0026lt;String, String\u0026gt;\u0026gt; { return ResponseEntity.ok(mapOf(\u0026#34;status\u0026#34; to \u0026#34;alive\u0026#34;)) } // Readiness probe - \u0026#34;A aplicacao esta pronta para receber trafego?\u0026#34; // Se falhar, Kubernetes remove o pod do service @GetMapping(\u0026#34;/health/ready\u0026#34;) fun readiness(): ResponseEntity\u0026lt;Map\u0026lt;String, Any\u0026gt;\u0026gt; { val dbReady = try { dataSource.connection.use { it.isValid(2) } } catch (e: Exception) { false } return if (dbReady) { ResponseEntity.ok(mapOf( \u0026#34;status\u0026#34; to \u0026#34;ready\u0026#34;, \u0026#34;database\u0026#34; to \u0026#34;connected\u0026#34; )) } else { ResponseEntity.status(HttpStatusCode.valueOf(503)).body(mapOf( \u0026#34;status\u0026#34; to \u0026#34;not_ready\u0026#34;, \u0026#34;database\u0026#34; to \u0026#34;disconnected\u0026#34; )) } } // Startup probe - \u0026#34;A aplicacao terminou de iniciar?\u0026#34; // Util para aplicacoes JVM que demoram para iniciar @GetMapping(\u0026#34;/health/started\u0026#34;) fun startup(): ResponseEntity\u0026lt;Map\u0026lt;String, String\u0026gt;\u0026gt; { return ResponseEntity.ok(mapOf(\u0026#34;status\u0026#34; to \u0026#34;started\u0026#34;)) } } Graceful Shutdown Kubernetes envia SIGTERM antes de matar um pod. Sua aplicação precisa tratar isso:\n// Configuração de graceful shutdown // application.yml: // server: // shutdown: graceful // spring: // lifecycle: // timeout-per-shutdown-phase: 30s @Component class GracefulShutdownHandler( private val processamentoService: ProcessamentoService ) { @PreDestroy fun onShutdown() { println(\u0026#34;Recebido sinal de shutdown, finalizando processamentos...\u0026#34;) runBlocking { processamentoService.finalizarPendentes() } println(\u0026#34;Shutdown completado com sucesso\u0026#34;) } } // Service que respeita shutdown @Service class ProcessamentoService { private val processando = AtomicBoolean(true) suspend fun finalizarPendentes() { processando.set(false) // Aguardar processamentos em andamento delay(5000) } suspend fun processar(item: Item) { if (!processando.get()) { throw ShutdownInProgressException() } // Processamento normal } } Configuração do Kubernetes Deployment O Deployment define como sua aplicação roda no Kubernetes. A configuração inclui:\n// Configuração da aplicacao para ler do environment @Configuration @ConfigurationProperties(prefix = \u0026#34;app\u0026#34;) data class AppConfig( var databaseUrl: String = \u0026#34;\u0026#34;, var databaseUsername: String = \u0026#34;\u0026#34;, var databasePassword: String = \u0026#34;\u0026#34;, var redisHost: String = \u0026#34;localhost\u0026#34;, var redisPort: Int = 6379, var featureFlags: FeatureFlags = FeatureFlags() ) { data class FeatureFlags( var novaUI: Boolean = false, var cacheHabilitado: Boolean = true ) } O manifesto Kubernetes correspondente define replicas, recursos (requests e limits de CPU e memória), probes de saude, variaveis de ambiente via ConfigMap e Secrets, e estrategia de rolling update.\nConfiguração de Recursos JVM A JVM dentro de containers precisa de atencao especial:\n// Configuração JVM otimizada para Kubernetes // Variavel de ambiente JAVA_OPTS no Deployment: // -XX:+UseContainerSupport -\u0026gt; Reconhece limits do container // -XX:MaxRAMPercentage=75.0 -\u0026gt; Usa ate 75% da RAM disponivel // -XX:InitialRAMPercentage=50.0 -\u0026gt; Inicia com 50% da RAM // -XX:+UseG1GC -\u0026gt; Garbage Collector eficiente // -XX:+UseStringDeduplication -\u0026gt; Economia de memoria // -Xss512k -\u0026gt; Stack size reduzido por thread // Verificar configuracao em runtime @PostConstruct fun logJvmConfig() { val runtime = Runtime.getRuntime() logger.info(\u0026#34;JVM Config - Max Memory: ${runtime.maxMemory() / 1024 / 1024}MB\u0026#34;) logger.info(\u0026#34;JVM Config - Available Processors: ${runtime.availableProcessors()}\u0026#34;) logger.info(\u0026#34;JVM Config - Total Memory: ${runtime.totalMemory() / 1024 / 1024}MB\u0026#34;) } Service e Ingress Para expor sua aplicação, você precisa de um Service e um Ingress. O Service abstrai o acesso aos pods, e o Ingress gerencia o roteamento HTTP externo com TLS.\nHorizontal Pod Autoscaler (HPA) Escale sua aplicação automaticamente baseado em métricas:\n// Exponha métricas customizadas para o HPA @Component class AutoscalingMetrics( private val meterRegistry: MeterRegistry, private val filaProcessamento: BlockingQueue\u0026lt;Tarefa\u0026gt; ) { init { // Metrica customizada para autoscaling meterRegistry.gauge(\u0026#34;app.fila.tamanho\u0026#34;, filaProcessamento) { it.size.toDouble() } meterRegistry.gauge(\u0026#34;app.fila.utilizacao\u0026#34;, filaProcessamento) { it.size.toDouble() / 1000.0 // Capacidade maxima = 1000 } } } O HPA pode escalar baseado em CPU, memória ou métricas customizadas via Prometheus Adapter.\nKtor no Kubernetes Se você usa Ktor em vez de Spring Boot, a configuração e mais leve:\n// Ktor otimizado para Kubernetes fun main() { embeddedServer( Netty, port = System.getenv(\u0026#34;PORT\u0026#34;)?.toIntOrNull() ?: 8080, host = \u0026#34;0.0.0.0\u0026#34; ) { install(ContentNegotiation) { json() } routing { // Health checks get(\u0026#34;/health/live\u0026#34;) { call.respond(mapOf(\u0026#34;status\u0026#34; to \u0026#34;alive\u0026#34;)) } get(\u0026#34;/health/ready\u0026#34;) { val healthy = checkDependencies() if (healthy) { call.respond(mapOf(\u0026#34;status\u0026#34; to \u0026#34;ready\u0026#34;)) } else { call.respond( HttpStatusCode.ServiceUnavailable, mapOf(\u0026#34;status\u0026#34; to \u0026#34;not_ready\u0026#34;) ) } } // API routes route(\u0026#34;/api/v1\u0026#34;) { produtoRoutes() pedidoRoutes() } } }.start(wait = true) } // Shutdown hook para Ktor Runtime.getRuntime().addShutdownHook(Thread { println(\u0026#34;Shutdown hook executado\u0026#34;) // Cleanup resources }) Logging para Kubernetes Em Kubernetes, logs devem ir para stdout/stderr em formato JSON:\n// Configuração de logging para Kubernetes // Use JSON format para que ferramentas como Fluentd ou Loki // possam processar os logs automaticamente // logback-spring.xml para producao deve usar: // - ConsoleAppender com LogstashEncoder // - Nao usar file appenders (Kubernetes gerencia logs) // - Incluir campos: timestamp, level, logger, message, stack_trace // Exemplo de log que fica bem em Kubernetes logger.info(\u0026#34;Pedido processado\u0026#34;, StructuredArguments.kv(\u0026#34;pedido_id\u0026#34;, pedido.id), StructuredArguments.kv(\u0026#34;duracao_ms\u0026#34;, duracao), StructuredArguments.kv(\u0026#34;status\u0026#34;, \u0026#34;sucesso\u0026#34;) ) // Resultado em JSON: // {\u0026#34;timestamp\u0026#34;:\u0026#34;2025-08-24T10:00:00\u0026#34;,\u0026#34;level\u0026#34;:\u0026#34;INFO\u0026#34;, // \u0026#34;message\u0026#34;:\u0026#34;Pedido processado\u0026#34;,\u0026#34;pedido_id\u0026#34;:\u0026#34;abc-123\u0026#34;, // \u0026#34;duracao_ms\u0026#34;:42,\u0026#34;status\u0026#34;:\u0026#34;sucesso\u0026#34;} Secrets e ConfigMaps Gerenciar configuração sensivel em Kubernetes:\n// Lendo secrets do Kubernetes como variaveis de ambiente @Configuration class SecretsConfig { @Value(\u0026#34;\\${DB_PASSWORD}\u0026#34;) private lateinit var dbPassword: String @Value(\u0026#34;\\${API_KEY}\u0026#34;) private lateinit var apiKey: String // Ou usando ConfigurationProperties } Para segredos mais sensiveis, considere usar External Secrets Operator ou HashiCorp Vault com integração Kubernetes.\nBoas Práticas Imagens pequenas: Use JRE alpine, não JDK completo Limits realistas: Defina CPU e memória baseados em testes de carga Health checks: Sempre configure liveness, readiness e startup probes Graceful shutdown: Trate SIGTERM adequadamente 12-Factor App: Configuração via environment variables Observabilidade: Logs JSON, métricas Prometheus, tracing OpenTelemetry Security context: Rode containers como non-root Conclusão Kotlin e Kubernetes formam uma combinacao poderosa para aplicações cloud-native. A JVM moderna e otimizada para containers, frameworks como Spring Boot e Ktor tem suporte nativo para Kubernetes, e as ferramentas de observabilidade da JVM são as mais maduras do mercado.\nInvista em entender bem o ecossistema Kubernetes e como configurar sua aplicação Kotlin para aproveitar ao maximo a plataforma. Ferramentas como kubectl, Helm e o próprio Kubernetes são escritas em Go, então conhecer a linguagem ajuda a entender e depurar a infraestrutura. Para workloads que exigem performance extrema com baixo consumo de memória em containers, Rust é outra opção que complementa bem o ecossistema Kotlin. O resultado sera aplicações resilientes, escalaveis e faceis de operar em producao.\n","permalink":"https://kotlin.dev.br/blog/kotlin-kubernetes/","summary":"\u003cp\u003eKubernetes — que é \u003ca href=\"https://golang.com.br/\" target=\"_blank\" rel=\"noopener\" onclick=\"umami.track('portfolio-site-click', { destination: 'golang.com.br' })\"\u003eescrito em Go\u003c/a\u003e — se consolidou como o padrão para orquestracao de containers, e aplicações Kotlin rodam excepcionalmente bem nesse ambiente. Com a JVM otimizada para containers e frameworks como Spring Boot e Ktor prontos para cloud-native, Kotlin e Kubernetes formam uma dupla poderosa. Vamos explorar como fazer isso na prática.\u003c/p\u003e\n\u003ch2 id=\"preparando-a-aplicação-kotlin-para-kubernetes\"\u003ePreparando a Aplicação Kotlin para Kubernetes\u003c/h2\u003e\n\u003ch3 id=\"dockerfile-otimizado\"\u003eDockerfile Otimizado\u003c/h3\u003e\n\u003cp\u003eO primeiro passo e criar uma imagem Docker eficiente:\u003c/p\u003e","title":"Kotlin e Kubernetes: Deploy e Orquestracao de Apps Kotlin | Kotlin Brasil"},{"content":"O que é ViewModel no Android? ViewModel é um componente da biblioteca Android Jetpack projetado para armazenar e gerenciar dados relacionados a interface de usuário de forma consciente do ciclo de vida. Quando uma Activity ou Fragment e destruida e recriada (por exemplo, ao girar a tela), o ViewModel sobrevive a essa recriação e mantém os dados intactos, evitando carregamentos desnecessários.\nO ViewModel separa a lógica de apresentação da camada de UI. A Activity ou Fragment cuida apenas de exibir dados e capturar interações do usuário, enquanto o ViewModel gerencia o estado, executa operações assíncronas e expõe dados reativos.\nConfiguração Adicione as dependências no build.gradle.kts:\ndependencies { implementation(\u0026#34;androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7\u0026#34;) implementation(\u0026#34;androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7\u0026#34;) implementation(\u0026#34;androidx.lifecycle:lifecycle-runtime-ktx:2.8.7\u0026#34;) // Para usar com Compose implementation(\u0026#34;androidx.activity:activity-compose:1.9.3\u0026#34;) } Sintaxe básica Um ViewModel básico herda da classe ViewModel():\nimport androidx.lifecycle.ViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow class ContadorViewModel : ViewModel() { private val _contador = MutableStateFlow(0) val contador: StateFlow\u0026lt;Int\u0026gt; = _contador.asStateFlow() fun incrementar() { _contador.value++ } fun decrementar() { _contador.value-- } fun resetar() { _contador.value = 0 } } Na Activity ou Fragment, você obtém o ViewModel assim:\nimport androidx.activity.viewModels class ContadorActivity : AppCompatActivity() { private val viewModel: ContadorViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycleScope.launch { viewModel.contador.collect { valor -\u0026gt; binding.textoContador.text = \u0026#34;Contagem: $valor\u0026#34; } } binding.botaoIncrementar.setOnClickListener { viewModel.incrementar() } } } Ciclo de vida do ViewModel O ViewModel e criado na primeira vez que a Activity ou Fragment solicita e sobrevive a recriacoes de configuração (rotação de tela, mudanca de idioma). Ele só e destruído quando a Activity e finalizada definitivamente (o usuário navega para tras ou chama finish()).\nActivity criada --\u0026gt; ViewModel criado Tela rotacionada --\u0026gt; Activity destruida e recriada, ViewModel SOBREVIVE Usuario sai --\u0026gt; Activity finalizada, ViewModel.onCleared() chamado O método onCleared() e chamado quando o ViewModel e destruído definitivamente, permitindo limpar recursos:\nclass MinhaViewModel : ViewModel() { private val conexao = abrirConexao() override fun onCleared() { super.onCleared() conexao.fechar() println(\u0026#34;ViewModel destruido, recursos liberados\u0026#34;) } } Exemplos práticos ViewModel com chamada de API data class Usuario(val id: Int, val nome: String, val email: String) sealed class UiState\u0026lt;out T\u0026gt; { data object Carregando : UiState\u0026lt;Nothing\u0026gt;() data class Sucesso\u0026lt;T\u0026gt;(val dados: T) : UiState\u0026lt;T\u0026gt;() data class Erro(val mensagem: String) : UiState\u0026lt;Nothing\u0026gt;() } class UsuarioViewModel( private val repositorio: UsuarioRepositorio ) : ViewModel() { private val _estado = MutableStateFlow\u0026lt;UiState\u0026lt;List\u0026lt;Usuario\u0026gt;\u0026gt;\u0026gt;(UiState.Carregando) val estado: StateFlow\u0026lt;UiState\u0026lt;List\u0026lt;Usuario\u0026gt;\u0026gt;\u0026gt; = _estado.asStateFlow() init { carregarUsuarios() } fun carregarUsuarios() { viewModelScope.launch { _estado.value = UiState.Carregando try { val usuarios = repositorio.buscarTodos() _estado.value = UiState.Sucesso(usuarios) } catch (e: Exception) { _estado.value = UiState.Erro(e.message ?: \u0026#34;Erro desconhecido\u0026#34;) } } } fun buscarPorId(id: Int) { viewModelScope.launch { _estado.value = UiState.Carregando try { val usuario = repositorio.buscarPorId(id) _estado.value = UiState.Sucesso(listOf(usuario)) } catch (e: Exception) { _estado.value = UiState.Erro(\u0026#34;Usuario nao encontrado\u0026#34;) } } } } ViewModel com Jetpack Compose @Composable fun TelaUsuarios( viewModel: UsuarioViewModel = viewModel() ) { val estado by viewModel.estado.collectAsStateWithLifecycle() Column(modifier = Modifier.fillMaxSize().padding(16.dp)) { Text( text = \u0026#34;Usuarios\u0026#34;, style = MaterialTheme.typography.headlineMedium ) Spacer(modifier = Modifier.height(16.dp)) when (val uiState = estado) { is UiState.Carregando -\u0026gt; { CircularProgressIndicator( modifier = Modifier.align(Alignment.CenterHorizontally) ) } is UiState.Sucesso -\u0026gt; { LazyColumn { items(uiState.dados) { usuario -\u0026gt; Card( modifier = Modifier .fillMaxWidth() .padding(vertical = 4.dp) ) { Column(modifier = Modifier.padding(16.dp)) { Text(text = usuario.nome) Text( text = usuario.email, style = MaterialTheme.typography.bodySmall ) } } } } } is UiState.Erro -\u0026gt; { Text( text = uiState.mensagem, color = MaterialTheme.colorScheme.error ) Button(onClick = { viewModel.carregarUsuarios() }) { Text(\u0026#34;Tentar novamente\u0026#34;) } } } } } ViewModel com SavedStateHandle O SavedStateHandle permite que dados do ViewModel sobrevivam até mesmo a morte do processo pelo sistema operacional:\nclass PesquisaViewModel( private val savedStateHandle: SavedStateHandle ) : ViewModel() { val termoPesquisa: StateFlow\u0026lt;String\u0026gt; = savedStateHandle.getStateFlow(\u0026#34;termo_pesquisa\u0026#34;, \u0026#34;\u0026#34;) private val _resultados = MutableStateFlow\u0026lt;List\u0026lt;String\u0026gt;\u0026gt;(emptyList()) val resultados: StateFlow\u0026lt;List\u0026lt;String\u0026gt;\u0026gt; = _resultados.asStateFlow() fun pesquisar(termo: String) { savedStateHandle[\u0026#34;termo_pesquisa\u0026#34;] = termo viewModelScope.launch { _resultados.value = executarPesquisa(termo) } } private suspend fun executarPesquisa(termo: String): List\u0026lt;String\u0026gt; { // Simula chamada de rede kotlinx.coroutines.delay(500) return listOf(\u0026#34;Resultado 1 para $termo\u0026#34;, \u0026#34;Resultado 2 para $termo\u0026#34;) } } ViewModel com injeção de dependência (Hilt) @HiltViewModel class ProdutoViewModel @Inject constructor( private val repositorio: ProdutoRepositorio, private val analytics: AnalyticsService ) : ViewModel() { private val _produtos = MutableStateFlow\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt;(emptyList()) val produtos: StateFlow\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt; = _produtos.asStateFlow() private val _carrinho = MutableStateFlow\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt;(emptyList()) val carrinho: StateFlow\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt; = _carrinho.asStateFlow() init { carregarProdutos() } private fun carregarProdutos() { viewModelScope.launch { _produtos.value = repositorio.listarTodos() analytics.registrarEvento(\u0026#34;produtos_carregados\u0026#34;) } } fun adicionarAoCarrinho(produto: Produto) { _carrinho.value = _carrinho.value + produto analytics.registrarEvento(\u0026#34;produto_adicionado_carrinho\u0026#34;) } fun removerDoCarrinho(produto: Produto) { _carrinho.value = _carrinho.value - produto } } Quando usar ViewModel Qualquer tela que exibe dados dinâmicos como listas de API, formularios e dados de banco local. Operações assíncronas que não devem ser canceladas ao rotacionar a tela, como chamadas de rede ou consultas a banco de dados. Compartilhamento de estado entre Fragments usando um ViewModel com escopo da Activity. Gerenciamento de estado de UI mantendo o estado de selecoes, filtros, paginação e navegação. separação de responsabilidades retirando lógica de negócio da Activity/Fragment. Casos de Uso no Mundo Real Telas de listagem com paginação e filtros: aplicativos de e-commerce e redes sociais usam ViewModels para gerenciar o estado de listas paginadas, filtros ativos e termos de busca. O ViewModel mantém a posicao da lista e os filtros aplicados mesmo quando o usuário rotaciona a tela, evitando recarregamento desnecessário.\nFormularios multi-etapas: aplicativos bancarios e de cadastro usam ViewModels para armazenar dados preenchidos em formularios de várias etapas. Se o usuário navega entre etapas ou rotaciona a tela, os dados já preenchidos sao preservados no ViewModel sem necessidade de persistencia em disco.\nCompartilhamento de estado entre Fragments: telas com abas (tabs) ou paineis laterais que precisam compartilhar dados usam um ViewModel com escopo da Activity. Quando o usuário seleciona um item em um Fragment, o outro Fragment pode observar a mudanca via o ViewModel compartilhado.\nControle de operações assíncronas em telas de detalhe: telas que exibem detalhes de um item e permitem acoes como favoritar, compartilhar ou excluir usam o ViewModel para coordenar essas operações. O viewModelScope garante que chamadas de rede em andamento não sejam canceladas por mudancas de configuração, mas sejam canceladas quando o usuário sai da tela.\nBoas Praticas Nunca passe Context, Activity, Fragment ou View para o ViewModel. O ViewModel sobrevive a Activity e manter essas referências causa vazamento de memória. Se precisar de contexto, use AndroidViewModel com Application. Exponha dados usando StateFlow imutavel (não MutableStateFlow). A Activity ou Fragment deve apenas observar, nunca modificar diretamente o estado. Use o padrão de backing property: private val _estado (mutavel) e val estado (somente leitura). Use sealed class ou sealed interface para modelar os estados da UI (Carregando, Sucesso, Erro). Isso torna o gerenciamento de estado explicito e o compilador garante que todos os estados sejam tratados no when. Colete flows respeitando o ciclo de vida usando collectAsStateWithLifecycle() no Compose ou repeatOnLifecycle em Activities/Fragments. Coletar sem respeitar o ciclo de vida pode causar atualizações de UI com a Activity destruida. Injete dependências no ViewModel através do construtor usando Hilt ou outra biblioteca de DI. Isso torna o ViewModel testavel, pois permite substituir dependências reais por mocks nos testes unitarios. Perguntas Frequentes P: O ViewModel sobrevive a rotação de tela. Ele também sobrevive a morte do processo? R: Nao. O ViewModel sobrevive apenas a mudancas de configuração (rotação, mudanca de idioma). Quando o sistema mata o processo para liberar memória, o ViewModel e destruído. Para persistir dados além da morte do processo, use SavedStateHandle, que armazena dados no Bundle do sistema e os restaura automaticamente.\nP: Posso compartilhar um ViewModel entre Activities diferentes? R: Nao diretamente. O ViewModel e vinculado ao ciclo de vida de uma Activity ou Fragment. Para compartilhar entre Fragments, use um ViewModel com escopo da Activity (activityViewModels()). Para compartilhar dados entre Activities, use mecanismos como repositórios, banco de dados ou SharedPreferences.\nP: Qual a diferenca entre LiveData e StateFlow no ViewModel? R: Ambos servem para expor dados reativos, mas StateFlow e parte do Kotlin Coroutines e não depende do Android. StateFlow sempre tem um valor inicial, e thread-safe por padrão e se integra melhor com Compose via collectAsStateWithLifecycle(). LiveData e lifecycle-aware nativamente mas esta sendo gradualmente substituido por StateFlow nas recomendacoes oficiais do Google.\nP: Devo colocar lógica de negócio no ViewModel? R: O ViewModel deve conter lógica de apresentação (como formatar dados para a UI, gerenciar estado de tela), mas lógica de negócio pura deve ficar em camadas inferiores como use cases ou repositórios. Isso segue o princípio de separação de responsabilidades e facilita a reutilização e testabilidade da lógica de negócio.\nErros comuns Passar Context ou View para o ViewModel // ERRADO: pode causar vazamento de memoria class MinhaViewModel( private val context: Context // NUNCA faca isso ) : ViewModel() // CORRETO: use AndroidViewModel se precisar de Application context class MinhaViewModel( application: Application ) : AndroidViewModel(application) { val context: Context get() = getApplication() } O ViewModel sobrevive a Activity. Se ele mantiver uma referência ao Context da Activity, essa Activity não sera coletada pelo garbage collector, causando vazamento de memória.\nObservar dados fora do ciclo de vida // ERRADO: collect sem respeitar ciclo de vida viewModel.estado.collect { /* pode atualizar UI com Activity destruida */ } // CORRETO: usar collectAsStateWithLifecycle no Compose val estado by viewModel.estado.collectAsStateWithLifecycle() // CORRETO: usar repeatOnLifecycle em Activities lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.estado.collect { estado -\u0026gt; atualizarUI(estado) } } } Criar ViewModel manualmente // ERRADO: perde a associacao com o ciclo de vida val viewModel = MinhaViewModel() // CORRETO: usar delegate ou ViewModelProvider val viewModel: MinhaViewModel by viewModels() Termos relacionados LiveData: classe observavel que respeita o ciclo de vida, alternativa mais antiga ao StateFlow para exposicao de dados no ViewModel. StateFlow: fluxo de estado do Kotlin Coroutines, recomendado atualmente para expor dados reativos no ViewModel. viewModelScope: CoroutineScope vinculado ao ciclo de vida do ViewModel, cancelado automaticamente em onCleared. SavedStateHandle: mecanismo para persistir estado do ViewModel entre reconstrucoes do processo. Hilt: biblioteca de injeção de dependência do Android que simplifica a criação de ViewModels com dependências. Repository pattern: padrão arquitetural que abstrai fontes de dados, frequentemente usado em conjunto com ViewModels. Conclusão O ViewModel e a peça central da arquitetura moderna de aplicativos Android com Kotlin. Ele resolve problemas fundamentais como perda de estado ao rotacionar a tela, vazamento de memória e acoplamento entre lógica de negócio e UI. Combinado com StateFlow, Compose e injeção de dependência, o ViewModel permite construir aplicativos reativos, testáveis e manteniveis. Dominar esse componente e essencial para qualquer desenvolvedor Android.\n","permalink":"https://kotlin.dev.br/glossario/viewmodel/","summary":"\u003ch2 id=\"o-que-é-viewmodel-no-android\"\u003eO que é ViewModel no Android?\u003c/h2\u003e\n\u003cp\u003eViewModel é um componente da biblioteca Android Jetpack projetado para armazenar e gerenciar dados relacionados a interface de usuário de forma consciente do ciclo de vida. Quando uma Activity ou Fragment e destruida e recriada (por exemplo, ao girar a tela), o ViewModel sobrevive a essa recriação e mantém os dados intactos, evitando carregamentos desnecessários.\u003c/p\u003e\n\u003cp\u003eO ViewModel separa a lógica de apresentação da camada de UI. A Activity ou Fragment cuida apenas de exibir dados e capturar interações do usuário, enquanto o ViewModel gerencia o estado, executa operações assíncronas e expõe dados reativos.\u003c/p\u003e","title":"ViewModel em Android/Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"Colocar código em producao e só o comeco. O verdadeiro desafio e saber o que esta acontecendo com sua aplicação em tempo real. Observabilidade, composta por logs, métricas e tracing distribuído, é o que permite entender, diagnosticar e resolver problemas rapidamente. Vamos ver como implementar observabilidade completa em aplicações Kotlin.\nOs Tres Pilares da Observabilidade 1. Logs Logs registram eventos discretos que acontecem na aplicação. São a forma mais básica de observabilidade, mas quando bem estruturados, são extremamente poderosos.\n// Logging estruturado com SLF4J e Kotlin import org.slf4j.LoggerFactory class PedidoService( private val pedidoRepository: PedidoRepository, private val pagamentoGateway: PagamentoGateway ) { private val logger = LoggerFactory.getLogger(PedidoService::class.java) suspend fun processarPedido(pedidoId: String): Pedido { logger.info(\u0026#34;Iniciando processamento do pedido\u0026#34;, kv(\u0026#34;pedidoId\u0026#34;, pedidoId), kv(\u0026#34;operacao\u0026#34;, \u0026#34;processar_pedido\u0026#34;) ) val pedido = pedidoRepository.findById(pedidoId) ?: run { logger.warn(\u0026#34;Pedido nao encontrado\u0026#34;, kv(\u0026#34;pedidoId\u0026#34;, pedidoId) ) throw PedidoNaoEncontradoException(pedidoId) } return try { val resultado = pagamentoGateway.processar(pedido) logger.info(\u0026#34;Pedido processado com sucesso\u0026#34;, kv(\u0026#34;pedidoId\u0026#34;, pedidoId), kv(\u0026#34;valor\u0026#34;, pedido.valor), kv(\u0026#34;status\u0026#34;, resultado.status) ) pedido.copy(status = PedidoStatus.PROCESSADO) } catch (e: Exception) { logger.error(\u0026#34;Erro ao processar pedido\u0026#34;, kv(\u0026#34;pedidoId\u0026#34;, pedidoId), kv(\u0026#34;erro\u0026#34;, e.message), e ) pedido.copy(status = PedidoStatus.ERRO) } } private fun kv(key: String, value: Any?): net.logstash.logback.argument.StructuredArgument { return net.logstash.logback.argument.StructuredArguments.kv(key, value) } } Logs Estruturados com Logback Para que logs sejam úteis em producao, eles devem ser estruturados em JSON:\n// Extension function para logging idiomatico em Kotlin inline fun \u0026lt;reified T\u0026gt; T.logger(): Logger { return LoggerFactory.getLogger(T::class.java) } class OrderProcessor { private val log = logger() fun process(order: Order) { log.info(\u0026#34;Processing order {} for customer {}\u0026#34;, order.id, order.customerId) } } A configuração do Logback (logback-spring.xml) deve usar o LogstashEncoder para producao, gerando logs JSON que podem ser facilmente indexados por ferramentas como Elasticsearch ou Loki.\n2. Métricas Métricas são dados numericos agregados ao longo do tempo. Respondem perguntas como \u0026ldquo;quantas requisicoes por segundo estamos recebendo?\u0026rdquo; e \u0026ldquo;qual a latencia media da API?\u0026rdquo;.\n// Métricas com Micrometer e Spring Boot @Configuration class MetricsConfig(private val meterRegistry: MeterRegistry) { @Bean fun pedidoCounter(): Counter { return Counter.builder(\u0026#34;pedidos.total\u0026#34;) .description(\u0026#34;Total de pedidos processados\u0026#34;) .tag(\u0026#34;aplicacao\u0026#34;, \u0026#34;pedido-service\u0026#34;) .register(meterRegistry) } @Bean fun pedidoTimer(): Timer { return Timer.builder(\u0026#34;pedidos.duracao\u0026#34;) .description(\u0026#34;Duracao do processamento de pedidos\u0026#34;) .publishPercentiles(0.5, 0.95, 0.99) // p50, p95, p99 .register(meterRegistry) } } @Service class PedidoService( private val pedidoCounter: Counter, private val pedidoTimer: Timer, private val meterRegistry: MeterRegistry ) { suspend fun criarPedido(request: CriarPedidoRequest): Pedido { return pedidoTimer.recordSuspend { try { val pedido = processarInterno(request) pedidoCounter.increment() meterRegistry.counter(\u0026#34;pedidos.status\u0026#34;, \u0026#34;status\u0026#34;, \u0026#34;sucesso\u0026#34; ).increment() pedido } catch (e: Exception) { meterRegistry.counter(\u0026#34;pedidos.status\u0026#34;, \u0026#34;status\u0026#34;, \u0026#34;erro\u0026#34;, \u0026#34;tipo_erro\u0026#34;, e.javaClass.simpleName ).increment() throw e } } } } // Extension function para medir suspend functions suspend fun \u0026lt;T\u0026gt; Timer.recordSuspend(block: suspend () -\u0026gt; T): T { val sample = Timer.start() try { return block() } finally { sample.stop(this) } } Métricas de Negocios Alem de métricas tecnicas, monitore métricas de negócio:\n@Component class BusinessMetrics(private val meterRegistry: MeterRegistry) { fun registrarVenda(valor: Double, categoria: String) { meterRegistry.counter(\u0026#34;vendas.total\u0026#34;, \u0026#34;categoria\u0026#34;, categoria ).increment() meterRegistry.summary(\u0026#34;vendas.valor\u0026#34;, \u0026#34;categoria\u0026#34;, categoria ).record(valor) } fun registrarCarrinhoAbandonado(valor: Double) { meterRegistry.counter(\u0026#34;carrinho.abandonado\u0026#34;).increment() meterRegistry.summary(\u0026#34;carrinho.abandonado.valor\u0026#34;).record(valor) } // Gauge para valores instantaneos fun monitorarFilaProcessamento(fila: Queue\u0026lt;*\u0026gt;) { meterRegistry.gauge(\u0026#34;fila.processamento.tamanho\u0026#34;, fila) { it.size.toDouble() } } } 3. Tracing Distribuído Em arquiteturas de microsserviços, tracing permite acompanhar uma requisicao através de múltiplos serviços:\n// OpenTelemetry com Spring Boot e Kotlin @RestController @RequestMapping(\u0026#34;/api/pedidos\u0026#34;) class PedidoController( private val pedidoService: PedidoService, private val tracer: Tracer ) { @PostMapping suspend fun criarPedido( @RequestBody request: CriarPedidoRequest ): ResponseEntity\u0026lt;PedidoDTO\u0026gt; { val span = tracer.spanBuilder(\u0026#34;criar-pedido\u0026#34;) .setAttribute(\u0026#34;pedido.cliente_id\u0026#34;, request.clienteId) .setAttribute(\u0026#34;pedido.itens_count\u0026#34;, request.itens.size.toLong()) .startSpan() return try { span.makeCurrent().use { val pedido = pedidoService.criarPedido(request) span.setAttribute(\u0026#34;pedido.id\u0026#34;, pedido.id) span.setAttribute(\u0026#34;pedido.valor\u0026#34;, pedido.valor) ResponseEntity.status(HttpStatus.CREATED).body(pedido.toDTO()) } } catch (e: Exception) { span.recordException(e) span.setStatus(StatusCode.ERROR, e.message ?: \u0026#34;Erro desconhecido\u0026#34;) throw e } finally { span.end() } } } Propagacao de Contexto com Coroutines Um desafio específico de Kotlin e a propagacao de contexto de tracing com coroutines:\n// Propagacao de contexto OpenTelemetry com coroutines import io.opentelemetry.extension.kotlin.asContextElement suspend fun processarComTracing(pedidoId: String) { val span = tracer.spanBuilder(\u0026#34;processar-pagamento\u0026#34;) .startSpan() withContext(span.asContextElement()) { try { // O contexto de tracing e propagado automaticamente val pagamento = pagamentoService.processar(pedidoId) notificacaoService.enviar(pedidoId, pagamento) } finally { span.end() } } } Stack de Observabilidade Prometheus + Grafana A combinacao mais popular para métricas:\n// Exposicao de métricas para Prometheus // application.yml // management: // endpoints: // web: // exposure: // include: health,info,prometheus // metrics: // export: // prometheus: // enabled: true // tags: // application: pedido-service // environment: production // Métricas customizadas expostas automaticamente @Component class CustomMetrics(private val registry: MeterRegistry) { init { // Metrica de uptime registry.gauge(\u0026#34;app.uptime.seconds\u0026#34;, this) { ManagementFactory.getRuntimeMXBean().uptime / 1000.0 } } } ELK Stack (Elasticsearch, Logstash, Kibana) Para logs centralizados, o ELK stack e o padrão da industria. Com Logback configurado para JSON e Filebeat para coleta, os logs de todas as instancias da sua aplicação ficam pesquisaveis em um único lugar.\nJaeger ou Zipkin Para tracing distribuído, Jaeger e Zipkin são as opções mais populares. OpenTelemetry permite trocar entre eles sem mudar o código da aplicação.\nAlertas Inteligentes Observabilidade sem alertas e como ter cameras de segurança que ninguem assiste:\n// Exemplo de cenarios que devem gerar alertas: // 1. Taxa de erro acima de 5% por mais de 5 minutos // 2. Latencia p99 acima de 2 segundos // 3. Uso de memoria acima de 90% // 4. Fila de processamento crescendo continuamente // Health check detalhado para alertas @Component class DetailedHealthIndicator( private val dataSource: DataSource, private val redisTemplate: RedisTemplate\u0026lt;String, String\u0026gt; ) : HealthIndicator { override fun health(): Health { val checks = mutableMapOf\u0026lt;String, Any\u0026gt;() // Verificar banco de dados val dbHealthy = try { dataSource.connection.use { it.isValid(3) } } catch (e: Exception) { false } checks[\u0026#34;database\u0026#34;] = if (dbHealthy) \u0026#34;UP\u0026#34; else \u0026#34;DOWN\u0026#34; // Verificar Redis val redisHealthy = try { redisTemplate.connectionFactory?.connection?.ping() != null } catch (e: Exception) { false } checks[\u0026#34;redis\u0026#34;] = if (redisHealthy) \u0026#34;UP\u0026#34; else \u0026#34;DOWN\u0026#34; return if (dbHealthy \u0026amp;\u0026amp; redisHealthy) { Health.up().withDetails(checks).build() } else { Health.down().withDetails(checks).build() } } } Conclusão Observabilidade não e luxo, e necessidade. Em aplicações Kotlin de producao, ter logs estruturados, métricas abrangentes e tracing distribuído e o que separa equipes que reagem a problemas de equipes que os previnem.\nComece com logs estruturados (e o mais rápido de implementar), adicione métricas com Micrometer e Prometheus, e por fim implemente tracing distribuído com OpenTelemetry. Cada camada adiciona visibilidade sobre o comportamento da sua aplicação e reduz o tempo de resolução de problemas. Muitas das melhores ferramentas de observabilidade — como Prometheus, Grafana e Jaeger — são escritas em Go, o que torna essa linguagem um excelente complemento para quem trabalha com infraestrutura. Invista em observabilidade e durma mais tranquilo sabendo que sua aplicação esta sendo monitorada.\n","permalink":"https://kotlin.dev.br/blog/kotlin-observabilidade/","summary":"\u003cp\u003eColocar código em producao e só o comeco. O verdadeiro desafio e saber o que esta acontecendo com sua aplicação em tempo real. Observabilidade, composta por logs, métricas e tracing distribuído, é o que permite entender, diagnosticar e resolver problemas rapidamente. Vamos ver como implementar observabilidade completa em aplicações Kotlin.\u003c/p\u003e\n\u003ch2 id=\"os-tres-pilares-da-observabilidade\"\u003eOs Tres Pilares da Observabilidade\u003c/h2\u003e\n\u003ch3 id=\"1-logs\"\u003e1. Logs\u003c/h3\u003e\n\u003cp\u003eLogs registram eventos discretos que acontecem na aplicação. São a forma mais básica de observabilidade, mas quando bem estruturados, são extremamente poderosos.\u003c/p\u003e","title":"Observabilidade para Aplicações Kotlin: Logs, Métricas e Traces | Kotlin Brasil"},{"content":"O que é Supervisor em Kotlin? No contexto de Kotlin Coroutines, o Supervisor é um mecanismo que modifica o comportamento padrão de propagacao de erros. Normalmente, quando uma coroutine filha falha, o erro propaga para o pai, que cancela todos os outros filhos. Com um Supervisor (via SupervisorJob ou supervisorScope), a falha de um filho não afeta os irmaos \u0026ndash; cada coroutine falha ou termina de forma independente.\nIsso e essencial em cenários onde tarefas são independentes é a falha de uma não deve derrubar as outras.\nO problema: propagacao padrão de erros Sem supervisor, o comportamento padrão e:\nimport kotlinx.coroutines.* fun main() = runBlocking { val scope = CoroutineScope(Job()) val job1 = scope.launch { delay(1000) println(\u0026#34;Job 1 finalizado\u0026#34;) // Nunca executa! } val job2 = scope.launch { delay(500) throw RuntimeException(\u0026#34;Erro no job 2\u0026#34;) } delay(2000) println(\u0026#34;Job 1 ativo: ${job1.isActive}\u0026#34;) // false println(\u0026#34;Job 1 cancelado: ${job1.isCancelled}\u0026#34;) // true -- cancelado pelo erro do irmao! } O erro no job2 propaga para o pai (o Job() do scope), que cancela job1 mesmo sem ter relação com o erro.\nSupervisorJob O SupervisorJob resolve isso:\nfun main() = runBlocking { val scope = CoroutineScope(SupervisorJob()) val job1 = scope.launch { delay(1000) println(\u0026#34;Job 1 finalizado com sucesso\u0026#34;) // Executa normalmente! } val job2 = scope.launch { delay(500) throw RuntimeException(\u0026#34;Erro no job 2\u0026#34;) } delay(2000) println(\u0026#34;Job 1 completo: ${job1.isCompleted}\u0026#34;) // true println(\u0026#34;Job 2 completo: ${job2.isCompleted}\u0026#34;) // true (com excecao) } Com SupervisorJob, o job2 falha, mas o job1 continua normalmente.\nsupervisorScope Para criar um escopo supervisor temporario dentro de uma coroutine:\nsuspend fun processarTodos(ids: List\u0026lt;Int\u0026gt;) = supervisorScope { ids.map { id -\u0026gt; async { processar(id) // Se um falhar, os outros continuam } }.forEach { deferred -\u0026gt; try { val resultado = deferred.await() println(\u0026#34;Sucesso: $resultado\u0026#34;) } catch (e: Exception) { println(\u0026#34;Erro: ${e.message}\u0026#34;) } } } suspend fun processar(id: Int): String { if (id == 3) throw RuntimeException(\u0026#34;Erro ao processar $id\u0026#34;) delay(100) return \u0026#34;Processado: $id\u0026#34; } fun main() = runBlocking { processarTodos(listOf(1, 2, 3, 4, 5)) } // Saida: // Sucesso: Processado: 1 // Sucesso: Processado: 2 // Erro: Erro ao processar 3 // Sucesso: Processado: 4 // Sucesso: Processado: 5 A diferenca entre coroutineScope e supervisorScope:\ncoroutineScope: se um filho falha, todos são cancelados. supervisorScope: se um filho falha, os outros continuam. Exemplo prático: carregamento paralelo de dados class DashboardService( private val usuarioApi: UsuarioApi, private val notificacaoApi: NotificacaoApi, private val estatisticaApi: EstatisticaApi ) { suspend fun carregarDashboard(userId: String): DashboardData = supervisorScope { val usuario = async { usuarioApi.buscar(userId) } val notificacoes = async { notificacaoApi.listar(userId) } val estatisticas = async { estatisticaApi.buscar(userId) } DashboardData( usuario = tentarObter(usuario), notificacoes = tentarObter(notificacoes) ?: emptyList(), estatisticas = tentarObter(estatisticas) ) } private suspend fun \u0026lt;T\u0026gt; tentarObter(deferred: Deferred\u0026lt;T\u0026gt;): T? { return try { deferred.await() } catch (e: Exception) { null // Retorna null se falhar, nao cancela as outras } } } Aqui, se a API de notificacoes estiver fora do ar, o dashboard ainda carrega com os dados do usuário e estatisticas. Sem supervisor, a falha nas notificacoes derrubaria tudo.\nSupervisorJob com CoroutineExceptionHandler Com supervisor, exceções não propagam para o pai. Você precisa de um CoroutineExceptionHandler para trata-las:\nfun main() = runBlocking { val handler = CoroutineExceptionHandler { _, excecao -\u0026gt; println(\u0026#34;Exceção capturada: ${excecao.message}\u0026#34;) } val scope = CoroutineScope(SupervisorJob() + handler) scope.launch { throw RuntimeException(\u0026#34;Erro no filho 1\u0026#34;) } scope.launch { delay(1000) println(\u0026#34;Filho 2 completou normalmente\u0026#34;) } delay(2000) } // Saida: // Exceção capturada: Erro no filho 1 // Filho 2 completou normalmente Sem o handler, a exceção seria impressa no stderr mas não seria tratada. O handler permite logar, notificar ou tomar outras acoes.\nSupervisor em ViewModels (Android) O viewModelScope do Android usa SupervisorJob por padrão:\nclass MeuViewModel : ViewModel() { // viewModelScope ja tem SupervisorJob // Se uma coroutine falhar, as outras nao são afetadas fun carregarDados() { viewModelScope.launch { // Se falhar, nao afeta outras coroutines do scope val dados = repositorio.buscar() _estado.value = Estado.Sucesso(dados) } } fun sincronizar() { viewModelScope.launch { // Independente do carregarDados sincronizador.executar() } } } SupervisorJob vs supervisorScope Caracteristica SupervisorJob supervisorScope Uso Criação de CoroutineScope Bloco suspend temporario Duracao Vive enquanto o scope existir Dura até todos os filhos terminarem Completacao Manual (cancel) Automatica Exception handler Precisa de CoroutineExceptionHandler Exceções em await()/join() Quando usar Supervisor Tarefas independentes: quando múltiplas operações são lancadas em paralelo e a falha de uma não deve afetar as outras. Dashboards e telas com dados de múltiplas fontes: se uma fonte falha, as outras devem continuar. Processamento em lote: ao processar uma lista de itens, a falha em um não deve parar o processamento dos outros. Serviços de longa duracao: workers ou serviços que lancam subtarefas independentes. ViewModels: escopos de ViewModel usam supervisor por padrão porque cada acao do usuário e independente. Casos de Uso no Mundo Real Carregamento de dashboards e telas compostas: aplicativos que exibem dados de múltiplas fontes independentes (perfil do usuário, notificacoes, recomendacoes) utilizam supervisorScope para que a falha de uma API não impeca o carregamento das demais secoes. O usuário ve a tela parcialmente preenchida em vez de uma tela de erro completa.\nProcessamento em lote de mensagens ou eventos: sistemas de backend que consomem filas de mensagens (Kafka, RabbitMQ) usam SupervisorJob no escopo de processamento para que a falha ao processar uma mensagem não interrompa o consumo das demais. Cada mensagem e tratada de forma independente e falhas sao registradas para reprocessamento.\nWorkers de sincronizacao em aplicativos mobile: aplicativos que sincronizam dados em segundo plano (fotos, contatos, arquivos) usam supervisor para que a falha na sincronizacao de um tipo de dado não cancele a sincronizacao dos demais. Por exemplo, se a sincronizacao de fotos falha por falta de espaco, os contatos continuam sincronizando.\nMicroservicos com health checks paralelos: servicos que verificam a saude de múltiplas dependências (banco de dados, cache, APIs externas) em paralelo usam supervisor para que a indisponibilidade de uma dependência não impeca a verificação das outras, permitindo relatorios parciais de saude.\nBoas Praticas Sempre combine SupervisorJob com um CoroutineExceptionHandler no escopo para capturar e registrar exceções de coroutines filhas. Sem o handler, exceções silenciosas podem passar despercebidas. Prefira supervisorScope para escopos temporarios dentro de funções suspend, e reserve SupervisorJob para escopos de longa duracao como ViewModels ou servicos. Trate exceções individualmente em cada coroutine filha usando try-catch em blocos launch, ou capture em await() para blocos async. O supervisor impede a propagacao, mas não substitui o tratamento de erro. Nao use supervisor quando as tarefas sao dependentes entre si. Se o resultado de uma coroutine alimenta outra, use coroutineScope para que a falha cancele todas as dependentes. Documente claramente no código por que um supervisor e usado em determinado ponto. Isso ajuda outros desenvolvedores a entender que as tarefas sao intencionalmente independentes e que falhas isoladas sao esperadas. Perguntas Frequentes P: Qual a diferenca entre usar SupervisorJob() e supervisorScope? R: SupervisorJob() cria um Job que pode ser usado na construcao de um CoroutineScope de longa duracao. Ele permanece ativo até ser cancelado explicitamente. Ja supervisorScope cria um escopo temporario que aguarda todos os filhos terminarem e entao retorna. Use SupervisorJob() para escopos persistentes (como ViewModels) e supervisorScope para blocos isolados dentro de funções suspend.\nP: O supervisor impede que exceções cheguem ao CoroutineExceptionHandler? R: Nao. O supervisor impede que a exceção de um filho cancele seus irmaos e o pai, mas a exceção ainda e entregue ao CoroutineExceptionHandler configurado no escopo. Se nenhum handler estiver configurado, a exceção e reportada ao handler global da JVM.\nP: Por que o viewModelScope do Android já usa SupervisorJob internamente? R: Porque cada acao do usuário (clicar em um botao, navegar, buscar dados) lanca uma coroutine independente no ViewModel. Se uma dessas acoes falhar, não faz sentido cancelar todas as outras operações em andamento. O SupervisorJob garante esse isolamento naturalmente.\nP: Posso usar supervisorScope dentro de um coroutineScope? R: Sim. Você pode aninhar escopos livremente. O supervisorScope interno tera comportamento de supervisor para seus filhos diretos, enquanto o coroutineScope externo mantera o comportamento padrão de cancelamento para seus filhos. Isso e útil quando parte de uma operação tem tarefas independentes e o restante e dependente.\nErros comuns Usar SupervisorJob como pai direto de async sem tratar exceções: com supervisor, exceções em async não propagam automaticamente. Se você não chamar await() ou não tiver um handler, a exceção sera silenciosa.\nConfundir SupervisorJob com try-catch: o supervisor não trata exceções; ele apenas impede a propagacao. Você ainda precisa tratar cada exceção individualmente.\nUsar supervisor quando as tarefas são dependentes: se o resultado de uma tarefa depende de outra, use coroutineScope normal. Nao faz sentido deixar uma continuar se sua dependência falhou.\nCriar SupervisorJob sem handler: exceções em coroutines filhas de um SupervisorJob que não são tratadas vao para o CoroutineExceptionHandler global. Configure um handler no scope.\nNao entender que supervisorScope espera todos os filhos: supervisorScope só retorna quando todos os filhos terminam (com sucesso ou falha). Se um filho trava, o scope inteiro trava.\nTermos relacionados Job: elemento do contexto que representa o ciclo de vida de uma coroutine. CoroutineScope: escopo que define o ciclo de vida de um grupo de coroutines. CoroutineExceptionHandler: handler que captura exceções não tratadas em coroutines. Structured Concurrency: princípio de que coroutines formam hierarquias controladas. async/Deferred: lancamento de coroutine com resultado, onde exceções são capturadas em await(). viewModelScope: escopo do Android que usa SupervisorJob internamente. O padrão Supervisor e uma ferramenta essencial para construir sistemas resilientes com Kotlin Coroutines. Ele permite que partes independentes do sistema falhem de forma isolada, sem derrubar todo o resto. Usar supervisor nos lugares certos torna sua aplicação mais robusta e seus usuários mais satisfeitos.\n","permalink":"https://kotlin.dev.br/glossario/supervisor/","summary":"\u003ch2 id=\"o-que-é-supervisor-em-kotlin\"\u003eO que é Supervisor em Kotlin?\u003c/h2\u003e\n\u003cp\u003eNo contexto de Kotlin Coroutines, o \u003cstrong\u003eSupervisor\u003c/strong\u003e é um mecanismo que modifica o comportamento padrão de propagacao de erros. Normalmente, quando uma coroutine filha falha, o erro propaga para o pai, que cancela todos os outros filhos. Com um Supervisor (via \u003cstrong\u003e\u003ccode\u003eSupervisorJob\u003c/code\u003e\u003c/strong\u003e ou \u003cstrong\u003e\u003ccode\u003esupervisorScope\u003c/code\u003e\u003c/strong\u003e), a falha de um filho \u003cstrong\u003enão afeta os irmaos\u003c/strong\u003e \u0026ndash; cada coroutine falha ou termina de forma independente.\u003c/p\u003e\n\u003cp\u003eIsso e essencial em cenários onde tarefas são independentes é a falha de uma não deve derrubar as outras.\u003c/p\u003e","title":"Supervisor em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é State em Kotlin? No contexto do Jetpack Compose, State (estado) é um valor que, quando muda, aciona automaticamente a recomposicao das funções Composable que o leem. O Compose rastreia quais Composables dependem de quais estados e reexecuta apenas os afetados quando o estado muda.\nSem estado reativo, a UI seria estática. Com State, você declara como a UI deve parecer para cada possível valor do estado, é o Compose cuida de manter tudo sincronizado.\nCriando estado com mutableStateOf import androidx.compose.runtime.* @Composable fun Contador() { // Cria um estado reativo que sobrevive a recomposicoes var contagem by remember { mutableStateOf(0) } Column { Text(text = \u0026#34;Contagem: $contagem\u0026#34;) Button(onClick = { contagem++ }) { Text(\u0026#34;Incrementar\u0026#34;) } } } Quando contagem muda (via contagem++), o Compose detecta a mudanca e reexecuta Contador(), atualizando o Text com o novo valor.\nTres elementos trabalham juntos:\nmutableStateOf(0): cria um holder de estado reativo com valor inicial 0. remember: preserva o estado entre recomposicoes (sem remember, o estado seria recriado a cada vez). by: delegação de propriedade que permite ler e escrever o valor diretamente. remember vs rememberSaveable @Composable fun CampoDeTexto() { // remember: sobrevive a recomposicoes, mas NAO a mudancas de configuracao var texto by remember { mutableStateOf(\u0026#34;\u0026#34;) } // rememberSaveable: sobrevive a recomposicoes E mudancas de configuracao var textoSalvo by rememberSaveable { mutableStateOf(\u0026#34;\u0026#34;) } Column { TextField(value = texto, onValueChange = { texto = it }) TextField(value = textoSalvo, onValueChange = { textoSalvo = it }) } } Use rememberSaveable quando o estado precisa sobreviver a rotação de tela ou a recriação da Activity.\nState hoisting (elevacao de estado) O padrão fundamental de gerenciamento de estado em Compose e elevar o estado para o componente pai:\n// Componente stateless: recebe estado e eventos como parametros @Composable fun CampoDeNome( nome: String, onNomeMudou: (String) -\u0026gt; Unit, modifier: Modifier = Modifier ) { OutlinedTextField( value = nome, onValueChange = onNomeMudou, label = { Text(\u0026#34;Nome\u0026#34;) }, modifier = modifier.fillMaxWidth() ) } // Componente pai: controla o estado @Composable fun FormularioDeCadastro() { var nome by remember { mutableStateOf(\u0026#34;\u0026#34;) } var email by remember { mutableStateOf(\u0026#34;\u0026#34;) } Column(modifier = Modifier.padding(16.dp)) { CampoDeNome( nome = nome, onNomeMudou = { nome = it } ) } } Beneficios do state hoisting:\nO componente filho e reutilizavel e testavel. O pai tem controle total sobre o estado. O fluxo de dados e unidirecional: estado desce, eventos sobem. derivedStateOf Para estados que são derivados de outros estados:\n@Composable fun ListaComFiltro() { var busca by remember { mutableStateOf(\u0026#34;\u0026#34;) } val todosItens = remember { listOf(\u0026#34;Kotlin\u0026#34;, \u0026#34;Java\u0026#34;, \u0026#34;Python\u0026#34;, \u0026#34;Rust\u0026#34;, \u0026#34;Go\u0026#34;) } // Recalcula apenas quando \u0026#39;busca\u0026#39; ou \u0026#39;todosItens\u0026#39; mudam val itensFiltrados by remember(busca) { derivedStateOf { todosItens.filter { it.contains(busca, ignoreCase = true) } } } Column { TextField(value = busca, onValueChange = { busca = it }) itensFiltrados.forEach { item -\u0026gt; Text(text = item) } } } derivedStateOf evita recomposicoes desnecessarias quando o calculo derivado produz o mesmo resultado.\nEstado com ViewModel Para estado que sobrevive a mudancas de configuração e representa lógica de negócio:\nclass ListaViewModel : ViewModel() { private val _itens = MutableStateFlow\u0026lt;List\u0026lt;String\u0026gt;\u0026gt;(emptyList()) val itens: StateFlow\u0026lt;List\u0026lt;String\u0026gt;\u0026gt; = _itens.asStateFlow() private val _carregando = MutableStateFlow(false) val carregando: StateFlow\u0026lt;Boolean\u0026gt; = _carregando.asStateFlow() fun carregar() { viewModelScope.launch { _carregando.value = true _itens.value = repositorio.buscarItens() _carregando.value = false } } } @Composable fun ListaTela(viewModel: ListaViewModel = viewModel()) { val itens by viewModel.itens.collectAsState() val carregando by viewModel.carregando.collectAsState() if (carregando) { CircularProgressIndicator() } else { LazyColumn { items(itens) { item -\u0026gt; Text(text = item) } } } } collectAsState() converte um StateFlow em State do Compose, integrando o ViewModel com a recomposicao.\nTipos de estado // MutableState: estado simples do Compose val estado: MutableState\u0026lt;Int\u0026gt; = mutableStateOf(0) // StateFlow: estado observavel de coroutines val fluxo: StateFlow\u0026lt;Int\u0026gt; = MutableStateFlow(0) // LiveData: estado observavel do Android (legado) val liveData: LiveData\u0026lt;Int\u0026gt; = MutableLiveData(0) // Todos podem ser convertidos para State do Compose: val a by remember { mutableStateOf(0) } val b by fluxo.collectAsState() val c by liveData.observeAsState(0) snapshotFlow: State para Flow Para observar mudancas de State como um Flow:\n@Composable fun BuscaComDebounce() { var query by remember { mutableStateOf(\u0026#34;\u0026#34;) } LaunchedEffect(Unit) { snapshotFlow { query } .debounce(300) .distinctUntilChanged() .collect { busca -\u0026gt; // Executar busca apos 300ms sem digitacao buscar(busca) } } TextField(value = query, onValueChange = { query = it }) } Quando usar cada tipo de estado Tipo Uso Escopo remember + mutableStateOf Estado de UI local Composable rememberSaveable Estado que sobrevive rotação Composable derivedStateOf Estado calculado de outros estados Composable ViewModel + StateFlow Logica de negócio e dados Tela snapshotFlow Converter State em Flow Bridge Casos de Uso no Mundo Real Formularios reativos: em telas de cadastro, login ou checkout, cada campo (nome, email, senha, endereco) e representado por um mutableStateOf. Mudancas no texto atualizam o estado, que por sua vez aciona recomposicao dos componentes visuais, incluindo validacao em tempo real e habilitacao/desabilitacao do botao de envio.\nTelas com carregamento e paginação: aplicações que consomem APIs usam StateFlow no ViewModel para representar estados como carregando, sucesso, erro e lista vazia. O Composable coleta esse fluxo com collectAsState() e renderiza a UI apropriada para cada estado, incluindo indicadores de progresso e mensagens de erro.\nTemas e preferencias do usuário: aplicações que permitem alternar entre tema claro e escuro ou alterar tamanho de fonte usam estado global (geralmente via CompositionLocal ou ViewModel compartilhado) para propagar mudancas de configuração por toda a arvore de Composables, recompondo apenas os componentes afetados.\nJogos e animacoes interativas: aplicações que exibem animacoes baseadas em interação do usuário (arrastar, pincar, rotacionar) usam mutableStateOf combinado com Animatable para rastrear posicao, escala e rotação de elementos visuais, com recomposicao automatica a cada frame de animacao.\nBoas Praticas Eleve o estado (state hoisting) sempre que um componente pai precisar controlar ou observar o valor: mantenha componentes filhos stateless, recebendo estado e callbacks como parametros. Isso torna os componentes reutilizaveis, testáveis e com fluxo de dados previsivel. Use derivedStateOf para calculos derivados de outros estados: em vez de recompor toda vez que um estado base muda, derivedStateOf recalcula o valor derivado apenas quando necessário e só aciona recomposicao se o resultado realmente mudar. Separe estado de UI de estado de negócio: estado de UI local (como se um dropdown esta aberto) deve ficar no Composable com remember. Estado de negócio (como a lista de itens carregados do servidor) deve ficar no ViewModel com StateFlow. Nunca mute colecoes dentro de mutableStateOf diretamente: o Compose detecta mudancas por referência. Alterar o conteudo de uma MutableList sem criar uma nova instancia não aciona recomposicao. Sempre crie uma nova colecao ao modificar. Prefira rememberSaveable para estado que precisa sobreviver a rotação de tela: remember perde o valor quando a Activity e recriada. Para dados como texto digitado pelo usuário, use rememberSaveable para preservar o estado automaticamente. Perguntas Frequentes P: Qual a diferenca entre mutableStateOf e MutableStateFlow? R: mutableStateOf e a primitiva de estado do Compose, integrada diretamente ao sistema de recomposicao. MutableStateFlow e uma primitiva de coroutines que representa um fluxo de estado. No ViewModel, prefira StateFlow para expor estado (pois o ViewModel não deve depender do Compose). No Composable, converta para State com collectAsState().\nP: Quando devo usar remember vs rememberSaveable vs ViewModel? R: Use remember para estado de UI efemero que não precisa sobreviver a rotação (ex: se um tooltip esta visivel). Use rememberSaveable para estado de UI que deve sobreviver a mudancas de configuração (ex: texto digitado em um campo). Use ViewModel para estado de negócio e dados carregados de APIs ou banco de dados.\nP: Por que meu Composable não recompoe quando mudo o estado? R: As causas mais comuns sao: (1) esqueceu de usar remember, entao o estado e recriado a cada recomposicao; (2) esta mutando uma colecao existente em vez de criar uma nova; (3) o valor sendo comparado e estruturalmente igual ao anterior, entao o Compose não detecta mudanca; (4) o estado esta sendo lido fora do escopo de composicao (ex: em um LaunchedEffect sem dependência correta).\nP: E seguro acessar mutableStateOf de várias threads? R: As leituras e escritas individuais em mutableStateOf sao thread-safe. Porem, operações compostas (ler e escrever baseado no valor lido) não sao atomicas. Para esses casos, use Snapshot.withMutableSnapshot ou gerencie a concorrencia no ViewModel com coroutines.\nErros comuns Esquecer remember: sem remember, o estado e recriado a cada recomposicao, perdendo o valor. // ERRADO @Composable fun Quebrado() { var x = mutableStateOf(0) // Recriado toda recomposicao! } // CORRETO @Composable fun Correto() { var x by remember { mutableStateOf(0) } } Colocar lógica de negócio no Composable: buscar dados, processar regras de negócio e acessar banco de dados devem ficar no ViewModel, não no Composable.\nNao elevar estado quando necessário: manter estado em componentes filhos quando o pai precisa controla-lo dificulta a comunicação e reutilização.\nmutação direta de coleções: mudar o conteudo de uma MutableList dentro de um mutableStateOf não aciona recomposicao. Você precisa criar uma nova lista.\n// ERRADO: nao aciona recomposicao val lista = remember { mutableStateOf(mutableListOf(1, 2, 3)) } lista.value.add(4) // Compose nao detecta! // CORRETO: cria nova lista val lista = remember { mutableStateOf(listOf(1, 2, 3)) } lista.value = lista.value + 4 // Nova referência, Compose detecta Usar remember para estado que precisa sobreviver a rotação: remember não sobrevive a mudancas de configuração. Use rememberSaveable ou ViewModel. Termos relacionados Composable: função que lê State e e recomposta quando o estado muda. Recomposicao: reexecucao de funções Composable quando seus estados de entrada mudam. ViewModel: gerencia estado e lógica de negócio fora da camada de UI. StateFlow: fluxo de estado de coroutines que pode ser convertido em State do Compose. remember: função que preserva valores entre recomposicoes. Flow: stream reativo que pode ser coletado como State usando collectAsState. State e o conceito central do Jetpack Compose. Entender como criar, elevar, derivar e gerenciar estado e o que separa interfaces reativas e corretas de interfaces com bugs de sincronizacao. O modelo declarativo do Compose torna o gerenciamento de estado mais previsivel e menos propenso a erros do que a abordagem imperativa tradicional.\n","permalink":"https://kotlin.dev.br/glossario/state/","summary":"\u003ch2 id=\"o-que-é-state-em-kotlin\"\u003eO que é State em Kotlin?\u003c/h2\u003e\n\u003cp\u003eNo contexto do Jetpack Compose, \u003cstrong\u003eState\u003c/strong\u003e (estado) é um valor que, quando muda, \u003cstrong\u003eaciona automaticamente a recomposicao\u003c/strong\u003e das funções Composable que o leem. O Compose rastreia quais Composables dependem de quais estados e reexecuta apenas os afetados quando o estado muda.\u003c/p\u003e\n\u003cp\u003eSem estado reativo, a UI seria estática. Com State, você declara como a UI deve parecer para cada possível valor do estado, é o Compose cuida de manter tudo sincronizado.\u003c/p\u003e","title":"State em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Serialization em Kotlin? Serialization (serialização) é o processo de converter objetos Kotlin em um formato que pode ser armazenado ou transmitido (como JSON, Protobuf ou CBOR), e desserializacao é o processo inverso. O kotlinx.serialization é a biblioteca oficial do Kotlin para essa tarefa, gerando código de serialização em tempo de compilação usando um plugin do compilador.\nDiferente de bibliotecas baseadas em reflexao (como Gson), kotlinx.serialization é mais rápida, type-safe e funciona em todas as plataformas Kotlin (JVM, iOS, JavaScript, WASM).\nConfiguração do projeto // build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;1.9.22\u0026#34; kotlin(\u0026#34;plugin.serialization\u0026#34;) version \u0026#34;1.9.22\u0026#34; } dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2\u0026#34;) } Uso básico com JSON import kotlinx.serialization.* import kotlinx.serialization.json.* @Serializable data class Usuario( val nome: String, val idade: Int, val email: String ) fun main() { val usuario = Usuario(\u0026#34;Ana\u0026#34;, 30, \u0026#34;ana@email.com\u0026#34;) // Serializar: objeto -\u0026gt; JSON string val json = Json.encodeToString(usuario) println(json) // {\u0026#34;nome\u0026#34;:\u0026#34;Ana\u0026#34;,\u0026#34;idade\u0026#34;:30,\u0026#34;email\u0026#34;:\u0026#34;ana@email.com\u0026#34;} // Desserializar: JSON string -\u0026gt; objeto val objeto = Json.decodeFromString\u0026lt;Usuario\u0026gt;(json) println(objeto) // Usuario(nome=Ana, idade=30, email=ana@email.com) } A anotacao @Serializable instrui o plugin do compilador a gerar um serializer para a classe. Sem ela, a classe não pode ser serializada.\nCustomizando nomes de campos @Serializable data class Produto( @SerialName(\u0026#34;nome_produto\u0026#34;) val nome: String, @SerialName(\u0026#34;preco_unitario\u0026#34;) val preco: Double, @SerialName(\u0026#34;em_estoque\u0026#34;) val emEstoque: Boolean ) fun main() { val produto = Produto(\u0026#34;Teclado\u0026#34;, 299.90, true) val json = Json.encodeToString(produto) println(json) // {\u0026#34;nome_produto\u0026#34;:\u0026#34;Teclado\u0026#34;,\u0026#34;preco_unitario\u0026#34;:299.9,\u0026#34;em_estoque\u0026#34;:true} } Valores opcionais e padrão @Serializable data class Configuração( val tema: String = \u0026#34;claro\u0026#34;, val fontSize: Int = 14, val idioma: String = \u0026#34;pt-BR\u0026#34; ) fun main() { val json = Json { encodeDefaults = false } // Serializar: campos com valor padrao podem ser omitidos val config = Configuração() println(json.encodeToString(config)) // {} (campos com valor padrao omitidos) // Desserializar: campos ausentes usam valor padrao val configParcial = json.decodeFromString\u0026lt;Configuração\u0026gt;(\u0026#34;\u0026#34;\u0026#34;{\u0026#34;tema\u0026#34;:\u0026#34;escuro\u0026#34;}\u0026#34;\u0026#34;\u0026#34;) println(configParcial) // Configuração(tema=escuro, fontSize=14, idioma=pt-BR) } Configurando o Json O objeto Json pode ser customizado com várias opções:\nval jsonConfig = Json { prettyPrint = true // JSON formatado com indentacao isLenient = true // Aceita JSON nao estritamente valido ignoreUnknownKeys = true // Ignora campos desconhecidos encodeDefaults = true // Inclui campos com valor padrao coerceInputValues = true // Coerce valores incorretos para padrao explicitNulls = false // Omite campos null namingStrategy = JsonNamingStrategy.SnakeCase // Converte camelCase para snake_case } @Serializable data class Resposta( val statusCode: Int, val mensagem: String, val dados: String? = null ) fun main() { val json = \u0026#34;\u0026#34;\u0026#34; { \u0026#34;status_code\u0026#34;: 200, \u0026#34;mensagem\u0026#34;: \u0026#34;Sucesso\u0026#34;, \u0026#34;campo_extra\u0026#34;: \u0026#34;ignorado\u0026#34; } \u0026#34;\u0026#34;\u0026#34;.trimIndent() val resposta = jsonConfig.decodeFromString\u0026lt;Resposta\u0026gt;(json) println(resposta) } Serializando coleções e tipos aninhados @Serializable data class Endereco( val rua: String, val cidade: String, val estado: String ) @Serializable data class Pedido( val id: Long, val itens: List\u0026lt;String\u0026gt;, val endereco: Endereco, val tags: Set\u0026lt;String\u0026gt; = emptySet(), val metadados: Map\u0026lt;String, String\u0026gt; = emptyMap() ) fun main() { val pedido = Pedido( id = 1001, itens = listOf(\u0026#34;Teclado\u0026#34;, \u0026#34;Mouse\u0026#34;), endereco = Endereco(\u0026#34;Rua A\u0026#34;, \u0026#34;São Paulo\u0026#34;, \u0026#34;SP\u0026#34;), tags = setOf(\u0026#34;eletronicos\u0026#34;, \u0026#34;informatica\u0026#34;), metadados = mapOf(\u0026#34;prioridade\u0026#34; to \u0026#34;alta\u0026#34;) ) val json = Json { prettyPrint = true } println(json.encodeToString(pedido)) } Polimorfismo com sealed classes @Serializable sealed class Notificacao { @Serializable @SerialName(\u0026#34;email\u0026#34;) data class Email(val destinatario: String, val assunto: String) : Notificacao() @Serializable @SerialName(\u0026#34;push\u0026#34;) data class Push(val token: String, val titulo: String) : Notificacao() @Serializable @SerialName(\u0026#34;sms\u0026#34;) data class Sms(val telefone: String, val mensagem: String) : Notificacao() } fun main() { val notificacoes: List\u0026lt;Notificacao\u0026gt; = listOf( Notificacao.Email(\u0026#34;ana@email.com\u0026#34;, \u0026#34;Bem-vinda\u0026#34;), Notificacao.Push(\u0026#34;token123\u0026#34;, \u0026#34;Nova mensagem\u0026#34;), Notificacao.Sms(\u0026#34;+5511999999999\u0026#34;, \u0026#34;Código: 1234\u0026#34;) ) val json = Json { prettyPrint = true } val jsonStr = json.encodeToString(notificacoes) println(jsonStr) // Desserializa com o tipo correto baseado no discriminador val desserializado = json.decodeFromString\u0026lt;List\u0026lt;Notificacao\u0026gt;\u0026gt;(jsonStr) desserializado.forEach { println(it::class.simpleName) } } Serializer customizado Para tipos que não são controlados por você ou que precisam de formatação especial:\nimport kotlinx.serialization.* import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.* import java.time.LocalDate object LocalDateSerializer : KSerializer\u0026lt;LocalDate\u0026gt; { override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(\u0026#34;LocalDate\u0026#34;, PrimitiveKind.STRING) override fun serialize(encoder: Encoder, value: LocalDate) { encoder.encodeString(value.toString()) } override fun deserialize(decoder: Decoder): LocalDate { return LocalDate.parse(decoder.decodeString()) } } @Serializable data class Evento( val nome: String, @Serializable(with = LocalDateSerializer::class) val data: LocalDate ) Outros formatos além de JSON kotlinx.serialization suporta múltiplos formatos:\n// Protobuf implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.6.2\u0026#34;) @Serializable data class Mensagem(@ProtoNumber(1) val texto: String, @ProtoNumber(2) val id: Int) val bytes = ProtoBuf.encodeToByteArray(Mensagem(\u0026#34;Ola\u0026#34;, 1)) val msg = ProtoBuf.decodeFromByteArray\u0026lt;Mensagem\u0026gt;(bytes) // CBOR implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-cbor:1.6.2\u0026#34;) val cborBytes = Cbor.encodeToByteArray(usuario) Quando usar kotlinx.serialization APIs REST: serializar e desserializar JSON em chamadas HTTP com Ktor ou Retrofit. Armazenamento local: salvar dados em arquivos ou bancos de dados em formato JSON. Kotlin Multiplatform: a única biblioteca de serialização que funciona em todas as plataformas. Performance crítica: geracao de código em tempo de compilação e mais rápida que reflexao. Comunicação entre serviços: usar Protobuf ou CBOR para formatos binarios eficientes. Casos de Uso no Mundo Real comunicação com APIs REST: em aplicações Android e backend com Ktor, kotlinx.serialization e usado para converter respostas JSON de APIs em data classes Kotlin e vice-versa. A integração com Ktor e nativa, dispensando configuração adicional para serialização de requisicoes e respostas.\nArmazenamento local estruturado: aplicações que precisam salvar estado ou configuracoes em disco usam kotlinx.serialization para converter objetos em JSON e gravar em arquivos ou DataStore. Na leitura, os dados sao desserializados de volta para objetos tipados, garantindo type safety.\nKotlin Multiplatform (KMP): em projetos multiplataforma que compartilham código entre Android, iOS, web e desktop, kotlinx.serialization e a única biblioteca de serialização que funciona em todos os targets. Modelos de dados compartilhados sao anotados com @Serializable uma única vez e funcionam em todas as plataformas.\ncomunicação entre microsservicos: backends Kotlin que se comunicam via gRPC ou mensageria (Kafka, RabbitMQ) usam formatos binarios como Protobuf ou CBOR com kotlinx.serialization para obter serialização eficiente e compacta, reduzindo latencia e consumo de banda.\nBoas Praticas Configure ignoreUnknownKeys = true ao consumir APIs externas: APIs de terceiros podem adicionar campos novos a qualquer momento. Sem essa configuração, campos desconhecidos causam exceção e quebram sua aplicação. Use @SerialName para desacoplar nomes Kotlin de nomes JSON: mantenha nomes de propriedades idiomaticos em Kotlin (camelCase) e use @SerialName para mapear para o formato da API (snake_case ou outro), evitando dependência direta do formato externo. Crie uma instancia reutilizavel de Json com suas configuracoes: em vez de criar uma nova instancia a cada serialização, defina um objeto Json configurado uma vez e reutilize-o em toda a aplicação. Isso melhora performance e garante consistencia. Prefira encodeDefaults = false para payloads menores: quando campos com valor padrão não precisam ser enviados, desativar a codificacao de defaults reduz o tamanho do JSON e o trafego de rede. Valide dados desserializados apos a conversao: kotlinx.serialization garante que o JSON e válido e que os tipos estao corretos, mas não válida regras de negócio. Adicione validacao explicita (como verificar se um email tem formato válido) apos a desserializacao. Perguntas Frequentes P: Qual a diferenca entre kotlinx.serialization e Gson/Jackson/Moshi? R: kotlinx.serialization gera código de serialização em tempo de compilação, enquanto Gson e Jackson usam reflexao em tempo de execução. Isso torna kotlinx.serialization mais rápida, type-safe e compativel com Kotlin Multiplatform. Alem disso, kotlinx.serialization entende nativamente recursos do Kotlin como valores padrão, nullability e sealed classes.\nP: Posso usar kotlinx.serialization com Retrofit? R: Sim. Existe o artefato com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter que adiciona suporte a kotlinx.serialization como converter factory do Retrofit. Com Ktor, a integração e nativa e não precisa de converters adicionais.\nP: Como serializo classes que não posso anotar com @Serializable (classes de terceiros)? R: Voce pode criar um KSerializer customizado para o tipo e registra-lo no modulo de serialização usando SerializersModule. Outra opção e criar uma classe wrapper ou surrogate anotada com @Serializable que represente os mesmos dados.\nP: kotlinx.serialization funciona com tipos genericos? R: Sim, mas com uma restricao: você precisa fornecer o serializer explicitamente para tipos genericos, pois o Kotlin não mantém informação de tipo generico em tempo de execução (type erasure). Use serializer\u0026lt;MeuTipo\u0026lt;Param\u0026gt;\u0026gt;() ou passe o serializer como parametro.\nErros comuns Esquecer a anotacao @Serializable: sem ela, o plugin não gera o serializer e você recebe um erro em tempo de execução.\nNao aplicar o plugin do compilador: apenas adicionar a dependência não basta. O plugin kotlin(\u0026quot;plugin.serialization\u0026quot;) deve ser aplicado no build.gradle.kts.\nIgnorar campos desconhecidos sem configurar: por padrão, campos extras no JSON causam exceção. Use ignoreUnknownKeys = true quando consumir APIs externas.\nConfundir com Gson ou Jackson: kotlinx.serialization tem API e anotações proprias. Misturar anotações de Gson com kotlinx.serialization não funciona.\nNao tratar nulls e ausentes: em JSON, um campo pode estar ausente ou ter valor null. Configure explicitNulls e coerceInputValues conforme necessário.\nTermos relacionados JSON: formato de dados textual amplamente usado em APIs web. Data Class: tipo ideal para serialização por ter propriedades claras e método copy. Sealed Class: permite serialização polimorfica com discriminador de tipo. KSP: processamento de simbolos, alternativa ao plugin de compilador para geracao de código. Kotlin Multiplatform: plataforma onde kotlinx.serialization brilha por funcionar em todos os targets. Gradle Plugin: o plugin de serialização e aplicado no sistema de build. kotlinx.serialization e a forma padrão e recomendada de serializar dados em Kotlin. Sua geracao de código em tempo de compilação, suporte multiplataforma e integração com o ecossistema Kotlin fazem dela a escolha natural para qualquer projeto moderno.\n","permalink":"https://kotlin.dev.br/glossario/serialization/","summary":"\u003ch2 id=\"o-que-é-serialization-em-kotlin\"\u003eO que é Serialization em Kotlin?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eSerialization\u003c/strong\u003e (serialização) é o processo de converter objetos Kotlin em um formato que pode ser armazenado ou transmitido (como JSON, Protobuf ou CBOR), e \u003cstrong\u003edesserializacao\u003c/strong\u003e é o processo inverso. O \u003cstrong\u003ekotlinx.serialization\u003c/strong\u003e é a biblioteca oficial do Kotlin para essa tarefa, gerando código de serialização em \u003cstrong\u003etempo de compilação\u003c/strong\u003e usando um plugin do compilador.\u003c/p\u003e\n\u003cp\u003eDiferente de bibliotecas baseadas em reflexao (como Gson), kotlinx.serialization é mais rápida, type-safe e funciona em todas as plataformas Kotlin (JVM, iOS, JavaScript, WASM).\u003c/p\u003e","title":"Serialization em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Value Class em Kotlin? Uma value class (anteriormente chamada de inline class) em Kotlin é um tipo wrapper que encapsula um único valor sem adicionar overhead de alocacao em tempo de execução. O compilador substitui a value class pelo valor contido sempre que possível, eliminando a criação de objetos extras na heap.\nEsse recurso resolve um problema clássico: você quer segurança de tipos para evitar confusao entre valores com o mesmo tipo primitivo (como misturar um ID de usuário com um ID de produto, ambos Int), mas não quer pagar o custo de performance de criar objetos wrapper.\nSintaxe básica Uma value class e declarada com a anotacao @JvmInline é a palavra-chave value:\n@JvmInline value class UserId(val id: Int) @JvmInline value class Email(val valor: String) @JvmInline value class Reais(val valor: Double) fun buscarUsuario(id: UserId): String { return \u0026#34;Usuario #${id.id}\u0026#34; } fun main() { val userId = UserId(42) println(buscarUsuario(userId)) // Usuario #42 // buscarUsuario(42) // ERRO: Int nao e UserId // buscarUsuario(Email(\u0026#34;test@mail.com\u0026#34;)) // ERRO: Email nao e UserId } A segurança de tipos e garantida em tempo de compilação, mas em tempo de execução o compilador usa o valor primitivo diretamente na maioria dos casos.\nComo funciona a otimização O compilador Kotlin trata value classes de forma especial. Considere este exemplo:\n@JvmInline value class Metros(val valor: Double) fun calcularArea(largura: Metros, altura: Metros): Double { return largura.valor * altura.valor } fun main() { val largura = Metros(5.0) val altura = Metros(3.0) println(calcularArea(largura, altura)) // 15.0 } No bytecode gerado, a função calcularArea recebe dois parametros Double diretamente, sem criar objetos Metros. A assinatura compilada se parece com:\n// Bytecode equivalente (simplificado) public static double calcularArea(double largura, double altura) { return largura * altura; } Porem, há situacoes onde o boxing (empacotamento em objeto) acontece: quando a value class e usada como tipo nullable, em coleções genericas ou como tipo de interface.\nExemplos práticos Dominio com tipos seguros @JvmInline value class CPF(val numero: String) { init { require(numero.length == 11) { \u0026#34;CPF deve ter 11 digitos\u0026#34; } require(numero.all { it.isDigit() }) { \u0026#34;CPF deve conter apenas digitos\u0026#34; } } fun formatado(): String { return \u0026#34;${numero.substring(0, 3)}.${numero.substring(3, 6)}.${numero.substring(6, 9)}-${numero.substring(9)}\u0026#34; } } @JvmInline value class CNPJ(val numero: String) { init { require(numero.length == 14) { \u0026#34;CNPJ deve ter 14 digitos\u0026#34; } } } @JvmInline value class Telefone(val numero: String) { init { require(numero.length in 10..11) { \u0026#34;Telefone invalido\u0026#34; } } } data class Cliente( val nome: String, val cpf: CPF, val telefone: Telefone ) fun registrarCliente(nome: String, cpf: CPF, telefone: Telefone): Cliente { return Cliente(nome, cpf, telefone) } fun main() { val cpf = CPF(\u0026#34;12345678901\u0026#34;) val telefone = Telefone(\u0026#34;11999887766\u0026#34;) val cliente = registrarCliente(\u0026#34;Ana Silva\u0026#34;, cpf, telefone) println(cliente) println(cpf.formatado()) // 123.456.789-01 // registrarCliente(\u0026#34;Ana\u0026#34;, telefone, cpf) // ERRO de compilacao: tipos trocados } Value class com interface Value classes podem implementar interfaces, mas isso causa boxing:\ninterface Exibivel { fun exibir(): String } @JvmInline value class Percentual(val valor: Double) : Exibivel { override fun exibir(): String = \u0026#34;${valor}%\u0026#34; } fun mostrar(item: Exibivel) { println(item.exibir()) } fun main() { val desconto = Percentual(15.0) println(desconto.exibir()) // 15.0% - sem boxing aqui mostrar(desconto) // boxing acontece aqui pois o parametro e Exibivel } Unidades de medida @JvmInline value class Quilometros(val valor: Double) { fun paraMilhas(): Milhas = Milhas(valor * 0.621371) fun paraMetros(): Double = valor * 1000.0 operator fun plus(outro: Quilometros) = Quilometros(valor + outro.valor) operator fun times(fator: Double) = Quilometros(valor * fator) } @JvmInline value class Milhas(val valor: Double) { fun paraQuilometros(): Quilometros = Quilometros(valor * 1.60934) } @JvmInline value class Celsius(val valor: Double) { fun paraFahrenheit(): Fahrenheit = Fahrenheit(valor * 9.0 / 5.0 + 32.0) } @JvmInline value class Fahrenheit(val valor: Double) { fun paraCelsius(): Celsius = Celsius((valor - 32.0) * 5.0 / 9.0) } fun main() { val distancia1 = Quilometros(100.0) val distancia2 = Quilometros(50.0) val total = distancia1 + distancia2 println(\u0026#34;${total.valor} km\u0026#34;) // 150.0 km println(\u0026#34;${total.paraMilhas().valor} milhas\u0026#34;) // 93.2... milhas val temp = Celsius(25.0) println(\u0026#34;${temp.valor}C = ${temp.paraFahrenheit().valor}F\u0026#34;) // 25.0C = 77.0F } Identificadores tipados para APIs @JvmInline value class PedidoId(val valor: Long) @JvmInline value class ProdutoId(val valor: Long) @JvmInline value class ClienteId(val valor: Long) data class ItemPedido( val produtoId: ProdutoId, val quantidade: Int ) fun criarPedido(clienteId: ClienteId, itens: List\u0026lt;ItemPedido\u0026gt;): PedidoId { println(\u0026#34;Pedido criado para cliente ${clienteId.valor} com ${itens.size} itens\u0026#34;) return PedidoId(System.currentTimeMillis()) } fun main() { val clienteId = ClienteId(1001) val itens = listOf( ItemPedido(ProdutoId(501), 2), ItemPedido(ProdutoId(502), 1) ) val pedidoId = criarPedido(clienteId, itens) println(\u0026#34;Pedido: ${pedidoId.valor}\u0026#34;) // criarPedido(ProdutoId(501), itens) // ERRO: ProdutoId nao e ClienteId } Quando usar value class Segurança de tipos para primitivos quando você quer distinguir entre valores que possuem o mesmo tipo subjacente, como IDs, moedas, unidades de medida. Domain-Driven Design para criar tipos que representam conceitos do dominio de negócio. APIs publicas onde a clareza dos tipos de parametro previne erros de uso. Validação no construtor usando blocos init para garantir invariantes do tipo. Substituicao de type aliases quando você precisa de segurança de tipos real, não apenas um apelido. Casos de Uso no Mundo Real Identificadores tipados em APIs REST: sistemas de backend usam value classes para criar tipos distintos para cada identificador (UserId, OrderId, ProductId). Isso impede erros como passar um ID de produto onde se espera um ID de usuário, um tipo de bug que seria silencioso com Long puro e só apareceria em producao.\nModelagem de dominio financeiro: aplicações financeiras usam value classes para representar moedas (Reais, Dolar, Euro) e valores monetarios com validacao embutida. O bloco init garante invariantes como valores não-negativos, e a tipagem impede operações entre moedas diferentes sem conversao explicita.\nValidacao de documentos e dados de entrada: formularios e APIs que recebem CPF, CNPJ, email ou telefone usam value classes com validacao no construtor para garantir que apenas dados validos circulem pelo sistema. Uma vez criado um CPF(\u0026quot;12345678901\u0026quot;), o restante do código pode confiar que o valor e válido.\nUnidades de medida em aplicações cientificas e de engenharia: sistemas que lidam com grandezas fisicas (metros, quilogramas, segundos) usam value classes com operadores customizados para prevenir erros de conversao de unidades. Isso evita incidentes classicos como confundir metros com pes em calculos de navegação.\nBoas Praticas Use value classes para qualquer tipo primitivo que represente um conceito de dominio distinto. Se você tem dois parametros Long que significam coisas diferentes, value classes previnem a troca acidental. Adicione validacao no bloco init para garantir invariantes do tipo. Isso cria um ponto único de validacao e garante que instancias invalidas nunca existam no sistema. Implemente operadores customizados (plus, minus, times, compareTo) quando fizer sentido semantico para o tipo. Isso torna o código mais expressivo e seguro. Esteja ciente de que boxing ocorre em contextos genericos (List\u0026lt;MinhaValueClass\u0026gt;), nullable (MinhaValueClass?) e quando a value class implementa uma interface. Em caminhos criticos de performance, considere usar arrays primitivos quando possível. Prefira value classes a type aliases quando seguranca de tipos for importante. O custo de digitacao adicional e compensado pela prevencao de bugs em tempo de compilação. Perguntas Frequentes P: Qual a diferenca entre value class e type alias? R: Um type alias e apenas um apelido para um tipo existente e não oferece seguranca de tipos adicional. typealias UserId = Int permite usar UserId e Int de forma intercambiavel. Ja uma value class cria um tipo distinto: value class UserId(val id: Int) impede que um Int comum seja passado onde se espera um UserId, gerando erro de compilação.\nP: Por que value classes só podem ter uma única propriedade no construtor? R: A otimização de inline depende de substituir o objeto wrapper pelo valor primitivo no bytecode. Com uma única propriedade, o compilador sabe exatamente qual valor usar como substituto. Com múltiplas propriedades, não seria possível representar o objeto como um único valor primitivo, e a otimização não funcionaria. Para múltiplas propriedades, use data classes.\nP: Posso usar value classes com frameworks de serialização como Kotlinx Serialization ou Jackson? R: Sim, mas requer configuração. Com Kotlinx Serialization, basta anotar a value class com @Serializable e ela sera serializada como o valor contido. Com Jackson, e necessário configurar o modulo jackson-module-kotlin e pode ser preciso adicionar anotacoes para controlar a serialização e desserializacao corretamente.\nP: A anotacao @JvmInline e sempre necessária? R: Na JVM (Kotlin/JVM), sim, e obrigatória. Ela indica ao compilador que deve gerar bytecode otimizado para a JVM. Em outros targets como Kotlin/JS e Kotlin/Native, a anotacao não e necessária pois essas plataformas tem suas proprias estrategias de otimização para value classes.\nErros comuns Tentar usar mais de uma propriedade // ERRADO: value class so aceita uma propriedade no construtor @JvmInline value class Coordenada(val x: Double, val y: Double) // erro de compilacao Value classes só podem encapsular um único valor. Para múltiplos valores, use uma data class.\nIgnorar o boxing em coleções genericas @JvmInline value class Idade(val valor: Int) fun main() { // Boxing acontece aqui: List\u0026lt;Idade\u0026gt; armazena objetos val idades: List\u0026lt;Idade\u0026gt; = listOf(Idade(25), Idade(30), Idade(18)) // Para performance critica, prefira IntArray val idadesArray = intArrayOf(25, 30, 18) } Esquecer a anotacao @JvmInline // ERRADO na JVM: falta @JvmInline value class Token(val valor: String) // erro de compilacao na JVM // CORRETO @JvmInline value class Token(val valor: String) Na JVM, a anotacao @JvmInline e obrigatória. Em Kotlin/Native e Kotlin/JS, ela não e necessária.\nHeranca de classes // ERRADO: value classes nao podem ser herdadas @JvmInline value class Base(val valor: Int) // class Derivada(valor: Int) : Base(valor) // erro // Value classes são implicitamente final Termos relacionados Type alias: cria um nome alternativo para um tipo existente, mas sem segurança de tipos adicional. Data class: classe que gera automaticamente equals, hashCode, toString e copy, mas com alocacao de objeto. Inline function: função cujo corpo e copiado no ponto de chamada, conceito diferente de inline/value class. Wrapper pattern: padrão de design que encapsula um valor, que e exatamente o que value classes fazem sem overhead. Kotlin/JVM: plataforma onde a anotacao @JvmInline e obrigatória para value classes. Conclusão Value classes são a solução ideal quando você precisa de segurança de tipos para valores simples sem sacrificar performance. Elas combinam a clareza de tipos de dominio com a eficiencia de tipos primitivos. Use-as para IDs, unidades de medida, documentos e qualquer conceito que se beneficie de tipagem forte. Lembre-se de que o boxing acontece em contextos genericos e nullable, e que cada value class encapsula exatamente um valor.\n","permalink":"https://kotlin.dev.br/glossario/value-class/","summary":"\u003ch2 id=\"o-que-é-value-class-em-kotlin\"\u003eO que é Value Class em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUma value class (anteriormente chamada de inline class) em Kotlin é um tipo wrapper que encapsula um único valor sem adicionar overhead de alocacao em tempo de execução. O compilador substitui a value class pelo valor contido sempre que possível, eliminando a criação de objetos extras na heap.\u003c/p\u003e\n\u003cp\u003eEsse recurso resolve um problema clássico: você quer segurança de tipos para evitar confusao entre valores com o mesmo tipo primitivo (como misturar um ID de usuário com um ID de produto, ambos \u003ccode\u003eInt\u003c/code\u003e), mas não quer pagar o custo de performance de criar objetos wrapper.\u003c/p\u003e","title":"Value Class em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Receiver em Kotlin? O receiver é o objeto sobre o qual uma função opera, acessivel dentro da função através da palavra-chave this. Em Kotlin, o conceito de receiver aparece em extension functions, lambdas with receiver e scope functions, sendo fundamental para a criação de APIs fluentes e DSLs.\nEm uma função normal, os parametros são explicitamente nomeados. Com um receiver, o objeto esta implicito no escopo da função, permitindo acessar suas propriedades e métodos diretamente sem qualificacao.\nReceiver em extension functions O exemplo mais comum de receiver e em extension functions:\nfun String.contarVogais(): Int { // \u0026#39;this\u0026#39; se refere ao String sobre o qual a funcao foi chamada return this.count { it in \u0026#34;aeiouAEIOU\u0026#34; } } fun main() { val texto = \u0026#34;Kotlin Brasil\u0026#34; println(texto.contarVogais()) // 5 } Aqui, String e o tipo do receiver. Dentro da função, this aponta para a instancia de String sobre a qual contarVogais() foi chamado. O this pode ser omitido:\nfun String.contarVogais(): Int { return count { it in \u0026#34;aeiouAEIOU\u0026#34; } // \u0026#39;this\u0026#39; implicito } Lambda with receiver Uma lambda with receiver e uma lambda que tem acesso ao receiver como this. A sintaxe do tipo e TipoReceiver.() -\u0026gt; TipoRetorno:\nfun construirMensagem(builder: StringBuilder.() -\u0026gt; Unit): String { val sb = StringBuilder() sb.builder() // Chama a lambda com sb como receiver return sb.toString() } fun main() { val mensagem = construirMensagem { // Dentro dessa lambda, \u0026#39;this\u0026#39; e o StringBuilder append(\u0026#34;Ola, \u0026#34;) append(\u0026#34;Kotlin!\u0026#34;) appendLine() append(\u0026#34;Tudo bem?\u0026#34;) } println(mensagem) } A lambda builder tem StringBuilder como receiver, entao dentro dela você pode chamar append, appendLine e outros métodos diretamente, como se estivesse dentro de um método da classe.\nScope functions e receivers As scope functions do Kotlin usam diferentes tipos de receiver:\ndata class Pessoa(var nome: String, var idade: Int) fun main() { val pessoa = Pessoa(\u0026#34;Ana\u0026#34;, 25) // apply: receiver e \u0026#39;this\u0026#39;, retorna o objeto pessoa.apply { nome = \u0026#34;Ana Maria\u0026#34; // this.nome idade = 26 // this.idade } // with: receiver e \u0026#39;this\u0026#39;, retorna o resultado da lambda val descricao = with(pessoa) { \u0026#34;$nome tem $idade anos\u0026#34; // this.nome, this.idade } // run: receiver e \u0026#39;this\u0026#39;, retorna o resultado da lambda val resultado = pessoa.run { \u0026#34;$nome ($idade)\u0026#34; } // let: parametro e \u0026#39;it\u0026#39;, nao usa receiver pessoa.let { p -\u0026gt; println(\u0026#34;${p.nome} tem ${p.idade} anos\u0026#34;) } // also: parametro e \u0026#39;it\u0026#39;, retorna o objeto pessoa.also { println(\u0026#34;Pessoa: ${it.nome}\u0026#34;) } } apply, with e run usam lambda with receiver (this). let e also usam lambda com parametro (it).\nCriando DSLs com receiver O poder real dos receivers aparece na criação de DSLs (Domain Specific Languages):\nclass HtmlBuilder { private val elementos = mutableListOf\u0026lt;String\u0026gt;() fun h1(texto: String) { elementos.add(\u0026#34;\u0026lt;h1\u0026gt;$texto\u0026lt;/h1\u0026gt;\u0026#34;) } fun p(texto: String) { elementos.add(\u0026#34;\u0026lt;p\u0026gt;$texto\u0026lt;/p\u0026gt;\u0026#34;) } fun ul(configurar: ListaBuilder.() -\u0026gt; Unit) { val builder = ListaBuilder() builder.configurar() elementos.add(builder.construir()) } fun construir(): String = elementos.joinToString(\u0026#34;\\n\u0026#34;) } class ListaBuilder { private val itens = mutableListOf\u0026lt;String\u0026gt;() fun li(texto: String) { itens.add(\u0026#34;\u0026lt;li\u0026gt;$texto\u0026lt;/li\u0026gt;\u0026#34;) } fun construir(): String { val conteudo = itens.joinToString(\u0026#34;\\n \u0026#34;) return \u0026#34;\u0026lt;ul\u0026gt;\\n $conteudo\\n\u0026lt;/ul\u0026gt;\u0026#34; } } fun html(configurar: HtmlBuilder.() -\u0026gt; Unit): String { val builder = HtmlBuilder() builder.configurar() return builder.construir() } fun main() { val pagina = html { h1(\u0026#34;Kotlin Brasil\u0026#34;) p(\u0026#34;Aprenda Kotlin em português.\u0026#34;) ul { li(\u0026#34;Coroutines\u0026#34;) li(\u0026#34;Flow\u0026#34;) li(\u0026#34;Compose\u0026#34;) } } println(pagina) } Cada bloco { } tem um receiver diferente, e os métodos disponiveis mudam conforme o contexto. Isso cria uma sintaxe que parece uma linguagem própria.\n@DslMarker para controle de escopo Sem controle, receivers de escopos externos podem vazar para escopos internos:\n@DslMarker annotation class HtmlDsl @HtmlDsl class HtmlBuilder { /* ... */ } @HtmlDsl class ListaBuilder { /* ... */ } // Agora, dentro de ul { }, voce NAO pode acessar h1() ou p() // Isso impede erros de escopo na DSL O @DslMarker restringe o acesso a receivers de escopos externos, tornando a DSL mais segura e previsivel.\nReceiver em funções de extensao de tipos genericos fun \u0026lt;T\u0026gt; T.tambem(bloco: (T) -\u0026gt; Unit): T { bloco(this) return this } fun \u0026lt;T\u0026gt; T.executar(bloco: T.() -\u0026gt; Unit): T { this.bloco() return this } A diferenca entre (T) -\u0026gt; Unit (parametro) e T.() -\u0026gt; Unit (receiver) e sutil mas importante:\n// Com parametro: acesso via \u0026#39;it\u0026#39; ou nome do parametro \u0026#34;texto\u0026#34;.tambem { valor -\u0026gt; println(valor.length) } // Com receiver: acesso via \u0026#39;this\u0026#39; (implicito) \u0026#34;texto\u0026#34;.executar { println(length) } Múltiplos receivers Kotlin permite que uma função tenha um receiver de extensao e um dispatch receiver (da classe):\nclass Logger { fun String.logInfo() { // \u0026#39;this\u0026#39; se refere ao String (extension receiver) // \u0026#39;this@Logger\u0026#39; se refere ao Logger (dispatch receiver) println(\u0026#34;[INFO] $this\u0026#34;) } } fun main() { val logger = Logger() with(logger) { \u0026#34;Mensagem de teste\u0026#34;.logInfo() // [INFO] Mensagem de teste } } Quando usar receivers Extension functions: para adicionar funcionalidade a tipos existentes sem heranca. DSLs: para criar APIs que leem como linguagem natural. Builders: para construir objetos complexos com sintaxe fluente. Scope functions: para operações rápidas em objetos sem criar variaveis intermediarias. Configuração: para blocos de configuração onde o contexto e claro e os métodos disponiveis são limitados. Casos de Uso no Mundo Real DSLs de construcao de UI: frameworks como Jetpack Compose e bibliotecas de HTML (kotlinx.html) usam lambdas with receiver extensivamente para criar interfaces declarativas. Cada bloco de construcao (Column, Row, Box) recebe uma lambda cujo receiver e o escopo de layout correspondente, permitindo que modificadores e filhos sejam adicionados de forma natural.\nconfiguração de clientes HTTP: bibliotecas como Ktor usam receivers para configurar requisicoes HTTP de forma fluente. O bloco de configuração do cliente, rotas, autenticação e plugins usam lambdas with receiver, permitindo que cada nivel de configuração exponha apenas os métodos relevantes ao contexto.\nBuilders de consultas de banco de dados: ORMs como Exposed usam receivers para construir queries SQL de forma type-safe. Dentro de um bloco transaction, o receiver fornece acesso a operações de banco; dentro de select, o receiver muda para expor operações de filtragem e projecao.\nExtension functions em projetos corporativos: equipes adicionam funções de extensao a classes de dominio para encapsular lógica recorrente (formatacao, validacao, conversao) sem alterar as classes originais, especialmente útil quando as classes vem de bibliotecas de terceiros.\nBoas Praticas Use @DslMarker ao criar DSLs com receivers aninhados: sem essa anotacao, receivers de escopos externos vazam para escopos internos, permitindo chamadas de métodos que não fazem sentido no contexto atual e gerando bugs sutis. Prefira this explicito em escopos ambiguos: quando há múltiplos receivers em escopos aninhados, usar this@NomeDaFuncao torna o código mais claro e evita que o receiver errado seja usado acidentalmente. Nao polua tipos comuns com muitas extension functions: adicionar dezenas de extensoes a String, Int ou List dificulta a descoberta de funcionalidade e pode gerar conflitos de nome. Agrupe extensoes relacionadas em arquivos específicos e com boa documentação. Use lambda with receiver para APIs de configuração: quando sua função recebe um bloco de configuração, declarar o parametro como Config.() -\u0026gt; Unit em vez de (Config) -\u0026gt; Unit torna o código do chamador mais limpo e idiomatico. Evite extension functions com efeitos colaterais inesperados: uma função String.salvarNoBanco() viola o princípio de menor surpresa. Extension functions devem ter comportamento previsivel e coerente com o tipo que estendem. Perguntas Frequentes P: Extension functions podem acessar membros privados da classe que estendem? R: Nao. Extension functions tem acesso apenas a membros publicos e internal do tipo receptor. Elas sao resolvidas estaticamente e não alteram a classe original. Se você precisa acessar membros privados, use uma função membro da própria classe.\nP: Qual a diferenca entre T.() -\u0026gt; Unit e (T) -\u0026gt; Unit? R: T.() -\u0026gt; Unit e uma lambda with receiver, onde dentro da lambda você acessa T via this (implicito). (T) -\u0026gt; Unit e uma lambda com parametro, onde você acessa T via nome do parametro ou it. Funcionalmente sao equivalentes, mas a versão com receiver produz código mais limpo em contextos de builder e DSL.\nP: O que sao Context Receivers e como se relacionam com receivers normais? R: Context Receivers sao um recurso experimental do Kotlin que permite declarar múltiplos receivers implicitos para uma função, sem precisar encadear extension functions. Enquanto um receiver normal e único (fun String.algo()), context receivers permitem que a função exija múltiplos contextos simultaneamente (context(Logger, Database) fun processar()).\nP: Extension functions sao resolvidas em tempo de compilação ou execução? R: Em tempo de compilação (dispatch estático). Isso significa que se uma classe filha e uma classe pai ambas tem uma extension function com a mesma assinatura, a função chamada depende do tipo declarado da variavel, não do tipo real do objeto em tempo de execução.\nErros comuns Receiver errado em escopos aninhados: quando você tem lambdas aninhadas com diferentes receivers, this se refere ao mais interno. Use this@NomeDaFuncao para acessar receivers externos.\nAbusar de extension functions: adicionar muitas extensions a tipos comuns como String ou Int polui o namespace e dificulta a descoberta de funcionalidade.\nNao usar @DslMarker: sem essa anotacao, DSLs permitem chamadas de métodos de escopos externos, levando a erros sutis.\nConfundir T.() -\u0026gt; Unit com (T) -\u0026gt; Unit: a primeira e uma lambda with receiver (acesso via this); a segunda e uma lambda com parametro (acesso via nome do parametro ou it).\nEsquecer que extension functions não tem acesso a membros privados: o receiver this da acesso apenas a membros publicos e internos do tipo, não a membros privados ou protegidos.\nTermos relacionados Extension Function: função que adiciona métodos a um tipo usando receiver. Context Receiver: recurso experimental que permite múltiplos receivers implícitos. Scope Functions: let, run, with, apply, also \u0026ndash; funções que manipulam receivers. DSL: Domain Specific Language, construida usando lambdas with receiver. this: palavra-chave que referência o receiver atual. Lambda: expressao funcional que pode ter receiver (T.() -\u0026gt; Unit). Receivers são um dos conceitos mais poderosos e distintos do Kotlin. Eles permitem que o código expresse intencao de forma clara e concisa, transformando operações complexas em blocos legiveis que parecem parte da linguagem. Dominar receivers e dominar a essencia do Kotlin idiomatico.\n","permalink":"https://kotlin.dev.br/glossario/receiver/","summary":"\u003ch2 id=\"o-que-é-receiver-em-kotlin\"\u003eO que é Receiver em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO \u003cstrong\u003ereceiver\u003c/strong\u003e é o objeto sobre o qual uma função opera, acessivel dentro da função através da palavra-chave \u003ccode\u003ethis\u003c/code\u003e. Em Kotlin, o conceito de receiver aparece em \u003cstrong\u003eextension functions\u003c/strong\u003e, \u003cstrong\u003elambdas with receiver\u003c/strong\u003e e \u003cstrong\u003escope functions\u003c/strong\u003e, sendo fundamental para a criação de APIs fluentes e DSLs.\u003c/p\u003e\n\u003cp\u003eEm uma função normal, os parametros são explicitamente nomeados. Com um receiver, o objeto esta implicito no escopo da função, permitindo acessar suas propriedades e métodos diretamente sem qualificacao.\u003c/p\u003e","title":"Receiver em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"GitHub Actions se tornou a ferramenta de CI/CD mais popular para projetos open source e comerciais. Para projetos Kotlin, a integração e poderosa e permite automatizar desde testes simples até pipelines completos de deploy. Neste guia, vamos construir workflows reais para projetos Kotlin. Se você precisa comparar GitHub Actions com GitLab CI, estruturar deploy por tags ou montar um pipeline mais amplo de Gradle, testes, detekt e ktlint, comece pelo guia completo de CI/CD para Kotlin.\nPor Que GitHub Actions para Kotlin GitHub Actions oferece vantagens específicas para projetos Kotlin:\nIntegração nativa com repositórios GitHub Runners gratuitos para projetos open source Cache de dependências Gradle nativo Marketplace com milhares de actions prontas Suporte a matrix builds para testar em múltiplas versões de JDK Workflow Básico para Kotlin Backend Vamos começar com um workflow para um projeto Spring Boot com Kotlin:\n// O workflow YAML fica em .github/workflows/ci.yml // Aqui vamos focar na configuracao do projeto Kotlin // build.gradle.kts otimizado para CI plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.1.0\u0026#34; kotlin(\u0026#34;plugin.spring\u0026#34;) version \u0026#34;2.1.0\u0026#34; id(\u0026#34;org.springframework.boot\u0026#34;) version \u0026#34;3.3.0\u0026#34; id(\u0026#34;io.spring.dependency-management\u0026#34;) version \u0026#34;1.1.4\u0026#34; id(\u0026#34;org.jetbrains.kotlinx.kover\u0026#34;) version \u0026#34;0.7.5\u0026#34; id(\u0026#34;io.gitlab.arturbosch.detekt\u0026#34;) version \u0026#34;1.23.4\u0026#34; } tasks.withType\u0026lt;Test\u0026gt; { useJUnitPlatform() testLogging { events(\u0026#34;passed\u0026#34;, \u0026#34;skipped\u0026#34;, \u0026#34;failed\u0026#34;) showStandardStreams = true } // Gerar relatorios para CI reports { junitXml.required.set(true) html.required.set(true) } } // Configuração kover para relatorio de cobertura koverReport { defaults { xml { onCheck = true } html { onCheck = true } } } O workflow GitHub Actions correspondente inclui etapas de checkout, setup JDK, cache Gradle, execução de testes e upload de relatorios. A configuração permite rodar em pushes para main e em pull requests.\nCache Eficiente de Gradle O cache de dependências Gradle e crítico para performance do CI:\n// gradle.properties - Otimizações para CI org.gradle.caching=true org.gradle.parallel=true org.gradle.daemon=false org.gradle.jvmargs=-Xmx2g -XX:+UseParallelGC kotlin.incremental=true GitHub Actions tem uma action oficial para cache de Gradle que armazena:\nDependências baixadas (~/.gradle/caches) Wrapper do Gradle (~/.gradle/wrapper) Build cache (.gradle/build-cache) Isso pode reduzir o tempo de build de 5-10 minutos para 1-2 minutos em builds subsequentes.\nWorkflow para Projeto Android Projetos Android com Kotlin tem necessidades específicas:\n// build.gradle.kts (modulo app) - Configuração para CI android { compileSdk = 34 defaultConfig { minSdk = 24 targetSdk = 34 testInstrumentationRunner = \u0026#34;androidx.test.runner.AndroidJUnitRunner\u0026#34; } buildTypes { release { isMinifyEnabled = true proguardFiles( getDefaultProguardFile(\u0026#34;proguard-android-optimize.txt\u0026#34;), \u0026#34;proguard-rules.pro\u0026#34; ) } } lint { abortOnError = true xmlReport = true htmlReport = true } testOptions { unitTests { isIncludeAndroidResources = true all { it.useJUnitPlatform() } } } } O workflow Android inclui:\nSetup do JDK e Android SDK Execução de lint Testes unitários Build do APK/AAB Opcionalmente, testes instrumentados com emulador Se você ainda está definindo quais testes devem rodar em cada etapa, use o guia completo de testes em Kotlin como referência para separar testes unitários, integração, Flow, Android e E2E sem deixar o pipeline lento demais.\nTestes Instrumentados no CI Para rodar testes instrumentados, você pode usar emuladores no GitHub Actions:\n// Teste instrumentado com Compose @HiltAndroidTest class LoginScreenTest { @get:Rule(order = 0) val hiltRule = HiltAndroidRule(this) @get:Rule(order = 1) val composeRule = createAndroidComposeRule\u0026lt;MainActivity\u0026gt;() @Test fun loginComCredenciaisValidas_deveNavegar() { composeRule.apply { onNodeWithTag(\u0026#34;email_field\u0026#34;) .performTextInput(\u0026#34;user@test.com\u0026#34;) onNodeWithTag(\u0026#34;password_field\u0026#34;) .performTextInput(\u0026#34;senha123\u0026#34;) onNodeWithTag(\u0026#34;login_button\u0026#34;) .performClick() waitForIdle() onNodeWithTag(\u0026#34;home_screen\u0026#34;) .assertIsDisplayed() } } } Automacoes Avançadas Publicacao Automatica de Releases Quando você cria uma tag, o workflow pode automaticamente:\n// build.gradle.kts - Versão baseada em tags val gitTag = System.getenv(\u0026#34;GITHUB_REF_NAME\u0026#34;) ?: \u0026#34;dev\u0026#34; version = if (gitTag.startsWith(\u0026#34;v\u0026#34;)) { gitTag.removePrefix(\u0026#34;v\u0026#34;) } else { \u0026#34;0.0.0-SNAPSHOT\u0026#34; } // Publicacao no Maven Central publishing { publications { create\u0026lt;MavenPublication\u0026gt;(\u0026#34;maven\u0026#34;) { from(components[\u0026#34;java\u0026#34;]) groupId = \u0026#34;com.example\u0026#34; artifactId = \u0026#34;minha-biblioteca\u0026#34; } } } Deploy Automatico para Cloud Workflows podem fazer deploy para diferentes provedores de cloud:\n// Exemplo de configuracao para deploy em produtao // Aplicação Kotlin com Spring Boot @Configuration @Profile(\u0026#34;production\u0026#34;) class ProductionConfig { @Bean fun corsConfig(): WebMvcConfigurer { return object : WebMvcConfigurer { override fun addCorsMappings(registry: CorsRegistry) { registry.addMapping(\u0026#34;/api/**\u0026#34;) .allowedOrigins(\u0026#34;https://meusite.com.br\u0026#34;) .allowedMethods(\u0026#34;GET\u0026#34;, \u0026#34;POST\u0026#34;, \u0026#34;PUT\u0026#34;, \u0026#34;DELETE\u0026#34;) .allowCredentials(true) } } } } // Health check para validação pos-deploy @RestController class HealthController( private val dataSource: DataSource ) { @GetMapping(\u0026#34;/health\u0026#34;) fun health(): Map\u0026lt;String, Any\u0026gt; { val dbHealthy = try { dataSource.connection.use { it.isValid(5) } } catch (e: Exception) { false } return mapOf( \u0026#34;status\u0026#34; to if (dbHealthy) \u0026#34;UP\u0026#34; else \u0026#34;DOWN\u0026#34;, \u0026#34;version\u0026#34; to (System.getenv(\u0026#34;APP_VERSION\u0026#34;) ?: \u0026#34;unknown\u0026#34;), \u0026#34;timestamp\u0026#34; to Instant.now().toString(), \u0026#34;checks\u0026#34; to mapOf( \u0026#34;database\u0026#34; to if (dbHealthy) \u0026#34;UP\u0026#34; else \u0026#34;DOWN\u0026#34; ) ) } } Dependabot para atualizações Configure Dependabot para manter dependências atualizadas. A configuração monitora atualizações de dependências Gradle e GitHub Actions semanalmente, agrupando-as por tipo.\nWorkflow para Kotlin Multiplatform Projetos KMP precisam de configuração específica:\n// build.gradle.kts para KMP kotlin { androidTarget() iosX64() iosArm64() iosSimulatorArm64() jvm() sourceSets { commonMain.dependencies { implementation(\u0026#34;io.ktor:ktor-client-core:3.0.0\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0\u0026#34;) } commonTest.dependencies { implementation(kotlin(\u0026#34;test\u0026#34;)) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0\u0026#34;) } } } O workflow KMP roda testes em múltiplas plataformas: JVM tests no Linux, iOS tests no macOS e Android tests no Linux.\nMatrix Builds Teste seu projeto Kotlin em múltiplas versões de JDK:\n// Código que pode se comportar diferente entre JDKs // Importante testar com matrix build class DateTimeService { fun formatarData(instant: Instant): String { val formatter = DateTimeFormatter .ofPattern(\u0026#34;dd/MM/yyyy HH:mm\u0026#34;) .withZone(ZoneId.of(\u0026#34;America/Sao_Paulo\u0026#34;)) return formatter.format(instant) } fun parsearData(texto: String): Instant { val formatter = DateTimeFormatter .ofPattern(\u0026#34;dd/MM/yyyy HH:mm\u0026#34;) .withZone(ZoneId.of(\u0026#34;America/Sao_Paulo\u0026#34;)) return Instant.from(formatter.parse(texto)) } } Uma strategy matrix com JDK 17, 21 e 23 garante compatibilidade.\nNotificacoes e Badges Configure notificacoes para falhas de pipeline:\nSlack: Actions para enviar notificacoes em canais de time Email: Notificacoes nativas do GitHub Badge no README: Mostra o status do build no repositório Segurança no CI Proteção de Segredos // NUNCA coloque segredos no codigo // Use GitHub Secrets e acesse via variaveis de ambiente @Configuration class ExternalServiceConfig( @Value(\u0026#34;\\${API_KEY:default}\u0026#34;) private val apiKey: String, @Value(\u0026#34;\\${API_SECRET:default}\u0026#34;) private val apiSecret: String ) { @Bean fun externalClient(): ExternalClient { return ExternalClient.builder() .apiKey(apiKey) .apiSecret(apiSecret) .build() } } Scanning de Vulnerabilidades GitHub oferece Dependabot alerts e code scanning que identificam vulnerabilidades em dependências e no código. Habilite essas features para manter seu projeto seguro.\nOtimização de Performance do CI Dicas para pipelines mais rápidos:\nUse cache agressivamente: Gradle, dependências Maven, imagens Docker Paralelismo: Execute jobs independentes em paralelo Skip desnecessário: Nao rode testes Android se só mudou código backend Runners self-hosted: Para projetos com muitos builds, considere runners próprios Conclusão GitHub Actions e uma ferramenta poderosa e flexivel para automatizar projetos Kotlin. De testes simples a pipelines complexos de deploy, a plataforma oferece tudo que você precisa para manter a qualidade e a velocidade de entrega.\nComece com um workflow básico de build e testes, e evolua gradualmente adicionando análise estática, cobertura de código, deploys automaticos e notificacoes. GitHub Actions funciona igualmente bem para projetos em Go, Python e Rust, então o conhecimento que você ganha aqui se transfere facilmente. A automação e um investimento que se paga exponencialmente ao longo do tempo, e GitHub Actions torna esse investimento acessivel para projetos de qualquer tamanho.\n","permalink":"https://kotlin.dev.br/blog/kotlin-github-actions/","summary":"\u003cp\u003eGitHub Actions se tornou a ferramenta de CI/CD mais popular para projetos open source e comerciais. Para projetos Kotlin, a integração e poderosa e permite automatizar desde testes simples até pipelines completos de deploy. Neste guia, vamos construir workflows reais para projetos Kotlin. Se você precisa comparar GitHub Actions com GitLab CI, estruturar deploy por tags ou montar um pipeline mais amplo de Gradle, testes, detekt e ktlint, comece pelo \u003ca href=\"/guias/guia-kotlin-ci-cd/\"\u003eguia completo de CI/CD para Kotlin\u003c/a\u003e.\u003c/p\u003e","title":"Kotlin com GitHub Actions: Automação Completa | Kotlin Brasil"},{"content":"O que é Property Delegate em Kotlin? Property Delegate (delegação de propriedade) é um mecanismo do Kotlin que permite delegar a lógica de leitura (get) e escrita (set) de uma propriedade para outro objeto. Em vez de implementar a lógica diretamente na propriedade, você usa a palavra-chave by para apontar para um objeto delegado que controla o comportamento.\nOs delegates mais conhecidos da biblioteca padrão são lazy, observable e vetoable, mas você pode criar os seus próprios para qualquer necessidade.\nSintaxe básica class Exemplo { // Delegando para lazy: inicializa na primeira leitura val configuracao: String by lazy { println(\u0026#34;Calculando...\u0026#34;) \u0026#34;Valor configurado\u0026#34; } } fun main() { val obj = Exemplo() println(obj.configuracao) // Imprime \u0026#34;Calculando...\u0026#34; e \u0026#34;Valor configurado\u0026#34; println(obj.configuracao) // Imprime apenas \u0026#34;Valor configurado\u0026#34; (ja calculado) } A palavra-chave by indica que a propriedade esta delegando suas operações de get (e set, se for var) para o objeto a direita.\nComo funciona internamente Quando você escreve val x by delegate, o compilador gera código equivalente a:\n// Você escreve: class Exemplo { val x: String by MeuDelegate() } // O compilador gera algo como: class Exemplo { private val x_delegate = MeuDelegate() val x: String get() = x_delegate.getValue(this, ::x) } Para propriedades var, o compilador também gera o setter:\n// var y by delegate gera: var y: String get() = y_delegate.getValue(this, ::y) set(value) { y_delegate.setValue(this, ::y, value) } Delegates da biblioteca padrão lazy Inicializa o valor na primeira leitura e cacheia para acessos subsequentes:\nval dadosPesados: List\u0026lt;String\u0026gt; by lazy { println(\u0026#34;Carregando dados pesados...\u0026#34;) carregarDoBanco() } Modos de thread safety do lazy:\n// Thread-safe (padrao): sincronizado val a by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { calcular() } // Sem sincronizacao: mais rapido, mas nao thread-safe val b by lazy(LazyThreadSafetyMode.NONE) { calcular() } // Publication: permite calculo duplicado, mas garante que todos veem o mesmo valor val c by lazy(LazyThreadSafetyMode.PUBLICATION) { calcular() } observable Notifica quando o valor muda:\nimport kotlin.properties.Delegates var nome: String by Delegates.observable(\u0026#34;Inicial\u0026#34;) { propriedade, valorAntigo, valorNovo -\u0026gt; println(\u0026#34;${propriedade.name} mudou de \u0026#39;$valorAntigo\u0026#39; para \u0026#39;$valorNovo\u0026#39;\u0026#34;) } fun main() { nome = \u0026#34;Ana\u0026#34; // Imprime: nome mudou de \u0026#39;Inicial\u0026#39; para \u0026#39;Ana\u0026#39; nome = \u0026#34;Bruno\u0026#34; // Imprime: nome mudou de \u0026#39;Ana\u0026#39; para \u0026#39;Bruno\u0026#39; } vetoable Permite rejeitar mudancas de valor:\nvar idade: Int by Delegates.vetoable(0) { _, _, novoValor -\u0026gt; novoValor \u0026gt;= 0 // So aceita valores nao-negativos } fun main() { idade = 25 // Aceito println(idade) // 25 idade = -5 // Rejeitado println(idade) // 25 (nao mudou) } notNull Similar ao lateinit, mas funciona com tipos primitivos delegados:\nvar contador: Int by Delegates.notNull\u0026lt;Int\u0026gt;() fun main() { // println(contador) // IllegalStateException! contador = 42 println(contador) // 42 } Criando um delegate customizado Para criar um delegate, implemente os operadores getValue e opcionalmente setValue:\nimport kotlin.reflect.KProperty class LoggingDelegate\u0026lt;T\u0026gt;(private var valor: T) { operator fun getValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;): T { println(\u0026#34;Lendo ${property.name}: $valor\u0026#34;) return valor } operator fun setValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;, novoValor: T) { println(\u0026#34;Escrevendo ${property.name}: $valor -\u0026gt; $novoValor\u0026#34;) valor = novoValor } } class Usuario { var nome: String by LoggingDelegate(\u0026#34;Sem nome\u0026#34;) var idade: Int by LoggingDelegate(0) } fun main() { val u = Usuario() u.nome = \u0026#34;Ana\u0026#34; // Escrevendo nome: Sem nome -\u0026gt; Ana println(u.nome) // Lendo nome: Ana u.idade = 30 // Escrevendo idade: 0 -\u0026gt; 30 } Exemplo prático: SharedPreferences delegate Um caso de uso real no Android e delegar propriedades para SharedPreferences:\nclass PreferenceDelegate( private val prefs: SharedPreferences, private val chave: String, private val padrao: String ) { operator fun getValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;): String { return prefs.getString(chave, padrao) ?: padrao } operator fun setValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;, valor: String) { prefs.edit().putString(chave, valor).apply() } } fun SharedPreferences.string(chave: String, padrao: String = \u0026#34;\u0026#34;) = PreferenceDelegate(this, chave, padrao) // Uso class Configurações(prefs: SharedPreferences) { var tema: String by prefs.string(\u0026#34;tema\u0026#34;, \u0026#34;claro\u0026#34;) var idioma: String by prefs.string(\u0026#34;idioma\u0026#34;, \u0026#34;pt-BR\u0026#34;) var nomeUsuario: String by prefs.string(\u0026#34;nome_usuario\u0026#34;, \u0026#34;\u0026#34;) } fun main() { val config = Configurações(obterPrefs()) config.tema = \u0026#34;escuro\u0026#34; // Salva automaticamente no SharedPreferences println(config.tema) // Le automaticamente do SharedPreferences } Delegate para Map Kotlin tem suporte embutido para delegar propriedades a um Map:\nclass Usuario(mapa: Map\u0026lt;String, Any?\u0026gt;) { val nome: String by mapa val idade: Int by mapa val email: String by mapa } fun main() { val dados = mapOf( \u0026#34;nome\u0026#34; to \u0026#34;Ana\u0026#34;, \u0026#34;idade\u0026#34; to 30, \u0026#34;email\u0026#34; to \u0026#34;ana@email.com\u0026#34; ) val usuario = Usuario(dados) println(usuario.nome) // Ana println(usuario.idade) // 30 } Para propriedades mutaveis, use MutableMap:\nclass Configuração(mapa: MutableMap\u0026lt;String, Any?\u0026gt;) { var tema: String by mapa var fontSize: Int by mapa } Interfaces ReadOnlyProperty e ReadWriteProperty Para maior clareza, seus delegates podem implementar interfaces oficiais:\nimport kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty class ValidatedString(private var valor: String) : ReadWriteProperty\u0026lt;Any?, String\u0026gt; { override fun getValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;): String = valor override fun setValue(thisRef: Any?, property: KProperty\u0026lt;*\u0026gt;, value: String) { require(value.isNotBlank()) { \u0026#34;${property.name} nao pode ser vazio\u0026#34; } valor = value } } class Formulario { var nome: String by ValidatedString(\u0026#34;\u0026#34;) var email: String by ValidatedString(\u0026#34;\u0026#34;) } Quando usar Property Delegates Inicialização preguicosa: lazy para valores calculados sob demanda. Observacao de mudancas: observable e vetoable para reagir a alteracoes de estado. Persistencia transparente: delegar para SharedPreferences, banco de dados ou cache. Validação automatica: verificar restricoes a cada escrita sem repetir código. Logging e auditoria: registrar acessos e modificacoes de propriedades. Casos de Uso no Mundo Real Persistencia transparente em Android: delegates que encapsulam SharedPreferences ou DataStore permitem que propriedades de uma classe de configuração leiam e escrevam automaticamente no armazenamento persistente. O desenvolvedor interage com a propriedade como se fosse um campo normal, sem se preocupar com a camada de persistencia.\nInjecao de dependência em frameworks como Koin: o Koin usa property delegates (by inject() e by viewModel()) para injetar dependências de forma preguicosa em Activities, Fragments e ViewModels. Isso elimina boilerplate de resolucao manual e torna o código mais declarativo.\nBinding de views em Android legado: antes do Jetpack Compose, bibliotecas como ViewBinding e ButterKnife usavam delegates para vincular views do XML a propriedades da Activity ou Fragment, evitando chamadas repetidas a findViewById.\nValidacao e sanitizacao automatica de dados: em sistemas de formularios ou APIs, delegates customizados podem validar valores a cada escrita (rejeitando dados invalidos) ou sanitizar entradas (removendo espacos extras, normalizando formatos) de forma transparente para o restante do código.\nBoas Praticas Use lazy com o modo de thread safety adequado: em contextos single-thread (como a thread principal do Android), use LazyThreadSafetyMode.NONE para evitar o overhead de sincronizacao desnecessaria. Implemente as interfaces ReadOnlyProperty ou ReadWriteProperty: ao criar delegates customizados, implementar essas interfaces torna o contrato explicito e facilita a leitura e manutenção do código. Evite efeitos colaterais pesados em getValue: o getter de uma propriedade delegada e chamado toda vez que a propriedade e lida. operações caras (como acesso a disco ou rede) devem ser cacheadas internamente pelo delegate. Prefira delegates a campos com lógica duplicada: se você perceber que várias propriedades da mesma classe possuem lógica identica de validacao, logging ou persistencia, extraia essa lógica para um delegate reutilizavel. Documente delegates customizados com exemplos de uso: como delegates alteram o comportamento implicito de propriedades, outros desenvolvedores precisam entender o que acontece por tras do by. Um KDoc com exemplo e essencial. Perguntas Frequentes P: Qual a diferenca entre lazy e lateinit? R: lazy e um delegate para propriedades val que inicializa o valor na primeira leitura e o cacheia. lateinit e um modificador para propriedades var que permite declarar a propriedade sem valor inicial, atribuindo-o depois. lazy garante que o valor e calculado exatamente uma vez; lateinit permite reatribuicao e não suporta tipos primitivos.\nP: Posso usar property delegates com propriedades de nivel de arquivo (top-level)? R: Sim. Property delegates funcionam em propriedades de classes, objetos, interfaces e também em propriedades top-level. Para propriedades top-level, o parametro thisRef do getValue/setValue sera null, já que não há um objeto proprietario.\nP: Como faco para delegar uma propriedade a outra propriedade da mesma classe? R: A partir do Kotlin 1.4, você pode usar a sintaxe val novoNome by ::nomeAntigo para delegar uma propriedade a outra usando referência de propriedade. Isso e útil para renomear propriedades mantendo compatibilidade com código existente.\nP: Property delegates impactam a performance da aplicação? R: O impacto e minimo para a maioria dos casos. O delegate adiciona uma camada de indirection (uma chamada de método extra para getValue/setValue), mas o JIT do JVM normalmente otimiza isso. O lazy com SYNCHRONIZED tem um custo de sincronizacao na primeira leitura, mas leituras subsequentes sao rapidas.\nErros comuns Nao entender que lazy e thread-safe por padrão: o modo SYNCHRONIZED tem overhead. Use NONE quando thread safety não e necessária.\nCriar delegates com efeitos colaterais pesados no getValue: o getter e chamado toda vez que a propriedade e lida. Operações caras devem ser cacheadas.\nEsquecer de implementar setValue para var: se o delegate não tem setValue, ele só funciona com val.\nConfundir delegação de propriedade com delegação de classe: class A by b delega a interface de uma classe; val x by delegate delega uma propriedade. São mecanismos diferentes.\nUsar lazy em propriedades que mudam: lazy e para val. Se você precisa de inicialização tardia com var, use lateinit ou Delegates.notNull.\nTermos relacionados lazy: delegate da biblioteca padrão para inicialização preguicosa. lateinit: alternativa ao delegate notNull para inicialização tardia. Delegation: conceito mais amplo que inclui delegação de classes e interfaces. observable/vetoable: delegates para monitorar e controlar mudancas de valor. val/var: delegates para val precisam apenas de getValue; delegates para var precisam também de setValue. KProperty: objeto de reflexao que representa a propriedade sendo delegada. Property Delegates são um dos recursos mais elegantes do Kotlin, permitindo separar a lógica transversal (logging, persistencia, válidação) da lógica de negócio de forma limpa e reutilizavel. Dominar esse conceito abre portas para APIs expressivas e código sem boilerplate.\n","permalink":"https://kotlin.dev.br/glossario/property-delegate/","summary":"\u003ch2 id=\"o-que-é-property-delegate-em-kotlin\"\u003eO que é Property Delegate em Kotlin?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eProperty Delegate\u003c/strong\u003e (delegação de propriedade) é um mecanismo do Kotlin que permite \u003cstrong\u003edelegar a lógica de leitura (get) e escrita (set) de uma propriedade para outro objeto\u003c/strong\u003e. Em vez de implementar a lógica diretamente na propriedade, você usa a palavra-chave \u003ccode\u003eby\u003c/code\u003e para apontar para um objeto delegado que controla o comportamento.\u003c/p\u003e\n\u003cp\u003eOs delegates mais conhecidos da biblioteca padrão são \u003ccode\u003elazy\u003c/code\u003e, \u003ccode\u003eobservable\u003c/code\u003e e \u003ccode\u003evetoable\u003c/code\u003e, mas você pode criar os seus próprios para qualquer necessidade.\u003c/p\u003e","title":"Property Delegate em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é noinline em Kotlin? O modificador noinline é usado em parametros lambda de funções inline para indicar que aquela lambda específica não deve ser inlineada. Quando uma função e marcada como inline, por padrão todas as lambdas passadas a ela são copiadas no local da chamada. O noinline desativa esse comportamento para um parametro específico, tratando a lambda como um objeto Function normal.\nIsso e necessário quando você precisa armazenar a lambda em uma variavel, passa-la para outra função não-inline ou usa-la como referência.\nPor que noinline existe? Quando uma lambda e inlineada, ela não existe como objeto em tempo de execução \u0026ndash; seu código e copiado diretamente. Isso significa que você não pode:\nArmazena-la em uma variavel ou propriedade. Passa-la como argumento para funções não-inline. Obter uma referência a ela. // ERRO: nao compila inline fun problema(acao: () -\u0026gt; Unit) { val referência = acao // Erro! Lambda inline nao pode ser armazenada executarDepois(acao) // Erro! Nao pode passar para funcao nao-inline } fun executarDepois(acao: () -\u0026gt; Unit) { // ... } A solução e marcar a lambda como noinline:\ninline fun funciona(noinline acao: () -\u0026gt; Unit) { val referência = acao // OK executarDepois(referência) // OK } Sintaxe e uso inline fun processar( inlineada: () -\u0026gt; Unit, // Sera inlineada normalmente noinline armazenavel: () -\u0026gt; Unit // Nao sera inlineada ) { inlineada() // Código copiado no local da chamada // armazenavel pode ser tratada como objeto val lista = listOf(armazenavel) lista.forEach { it() } } Exemplo prático: sistema de callbacks registrados class GerenciadorDeEventos { private val callbacks = mutableListOf\u0026lt;() -\u0026gt; Unit\u0026gt;() // inline para a lambda de configuracao, noinline para o callback inline fun registrar( configurar: () -\u0026gt; Unit, noinline callback: () -\u0026gt; Unit ) { configurar() // Inlineada: sem overhead de objeto callbacks.add(callback) // Noinline: pode ser armazenada } fun dispararTodos() { callbacks.forEach { it() } } } fun main() { val gerenciador = GerenciadorDeEventos() gerenciador.registrar( configurar = { println(\u0026#34;Configurando evento...\u0026#34;) }, callback = { println(\u0026#34;Evento disparado!\u0026#34;) } ) gerenciador.dispararTodos() } Nesse exemplo, a lambda configurar e executada imediatamente e se beneficia do inline (sem alocacao de objeto). Ja o callback precisa ser armazenado para execução posterior, entao deve ser noinline.\nnoinline vs crossinline Ambos modificam o comportamento de lambdas em funções inline, mas de maneiras diferentes:\ninline fun comparação( noinline lambdaNo: () -\u0026gt; Unit, // NAO inlineada, vira objeto Function crossinline lambdaCross: () -\u0026gt; Unit // Inlineada, mas sem non-local return ) { // noinline: pode ser armazenada como referência val ref: () -\u0026gt; Unit = lambdaNo // OK // val ref2: () -\u0026gt; Unit = lambdaCross // ERRO! crossinline ainda e inline // crossinline: pode ser usada em outro contexto val runnable = Runnable { lambdaCross() } // OK // noinline tambem pode, mas sem beneficio de inline // noinline: non-local return NAO e possivel (e um objeto normal) // crossinline: non-local return NAO e possivel (proibido pelo crossinline) // inline normal: non-local return E possivel } Resumo:\nCaracteristica inline noinline crossinline Código copiado? Sim Nao Sim Non-local return? Sim Nao Nao Pode armazenar? Nao Sim Nao Overhead de objeto? Nao Sim Nao Quando noinline faz mais sentido que crossinline // Use noinline quando precisa ARMAZENAR a lambda class Cache\u0026lt;T\u0026gt; { private var provider: (() -\u0026gt; T)? = null inline fun configurar(noinline provider: () -\u0026gt; T) { this.provider = provider // Precisa armazenar } fun obter(): T = provider?.invoke() ?: throw IllegalStateException(\u0026#34;Provider nao configurado\u0026#34;) } // Use crossinline quando precisa EXECUTAR em outro contexto sem armazenar inline fun executarEmBackground(crossinline bloco: () -\u0026gt; Unit) { Thread { bloco() }.start() // Executa, nao armazena } Impacto na performance A diferenca de performance entre lambdas inline e noinline e a alocacao de objetos:\ninline fun comNoinline(noinline acao: () -\u0026gt; Unit) { acao() // Chama como objeto Function: cria instancia no heap } inline fun semNoinline(acao: () -\u0026gt; Unit) { acao() // Código copiado diretamente: sem alocacao } fun main() { // Com noinline: alocacao de objeto Function a cada chamada repeat(1_000_000) { comNoinline { /* trabalho */ } } // Sem noinline: nenhuma alocacao extra repeat(1_000_000) { semNoinline { /* trabalho */ } } } Em loops apertados com milhoes de iteracoes, a diferenca pode ser significativa. Porem, para a maioria do código de aplicação, o impacto e negligenciavel.\nMultiplas lambdas: inline seletivo Uma função inline pode ter algumas lambdas inline e outras noinline:\ninline fun \u0026lt;T\u0026gt; buscarComFallback( buscar: () -\u0026gt; T?, // Inlineada: executada diretamente noinline fallback: () -\u0026gt; T, // Noinline: pode ser armazenada noinline onErro: (Exception) -\u0026gt; Unit // Noinline: pode ser passada adiante ) : T { return try { buscar() ?: fallback() } catch (e: Exception) { onErro(e) fallback() } } Quando usar noinline Armazenar lambdas: quando a lambda precisa ser salva em uma propriedade, lista ou mapa para uso posterior. Passar para funções não-inline: quando a lambda sera argumento de outra função que não e inline. Retornar lambdas: quando uma função inline precisa retornar uma das lambdas recebidas. Coleções de callbacks: quando você gerencia uma lista de callbacks que serao executados depois. Casos de Uso no Mundo Real Sistemas de eventos e callbacks: em frameworks de UI como Jetpack Compose ou sistemas de mensageria, funções inline frequentemente recebem lambdas que precisam ser armazenadas em listas de listeners para execução futura. O noinline permite que essas lambdas sejam registradas enquanto outras lambdas da mesma função continuam sendo inlineadas para performance.\nFrameworks de injecao de dependência: bibliotecas como Koin usam funções inline com parametros reified para resolver tipos genericos, mas precisam armazenar factories (lambdas) em registros internos. O noinline e usado nos parametros de factory para que possam ser guardados em mapas de definicoes.\nPipelines de processamento de dados: ao construir pipelines funcionais onde algumas transformacoes sao executadas imediatamente (inline) e outras sao armazenadas para execução condicional ou adiada, o noinline permite misturar os dois comportamentos na mesma função.\nLogging e monitoramento em bibliotecas de alta performance: funções utilitarias inline podem receber uma lambda de acao (inlineada para performance em hot paths) e uma lambda noinline de fallback ou erro que sera passada para um sistema de monitoramento externo.\nBoas Praticas Prefira crossinline quando não precisa armazenar a lambda: se o objetivo e apenas impedir non-local return mas a lambda sera executada no mesmo escopo, crossinline mantém o beneficio de performance do inline. Evite marcar todas as lambdas como noinline: se todas as lambdas de uma função inline sao noinline, a função não deveria ser inline (a menos que use reified). O compilador emite um warning nesses casos. Documente por que uma lambda e noinline: como o noinline tem impacto em performance e semantica, adicione um comentario breve explicando a necessidade (armazenamento, passagem para função não-inline, etc.). Minimize o número de lambdas noinline em funções inline de hot path: cada lambda noinline aloca um objeto Function no heap. Em loops com milhoes de iteracoes, prefira redesenhar a API para reduzir alocacoes. Teste o comportamento de non-local return: lembre-se de que lambdas noinline não suportam non-local return. Garanta que os chamadores da sua função não dependam desse comportamento. Perguntas Frequentes P: Posso usar noinline em uma função que não e inline? R: Nao. O modificador noinline só faz sentido em parametros lambda de funções marcadas como inline. Em funções normais, todas as lambdas já sao tratadas como objetos Function, entao noinline seria redundante e o compilador emite um erro.\nP: Qual o impacto real de performance do noinline em relacao ao inline? R: Cada chamada com lambda noinline aloca um objeto Function no heap, que posteriormente precisa ser coletado pelo garbage collector. Em código de aplicação comum, o impacto e negligenciavel. Porem, em hot paths com milhoes de iteracoes por segundo, a diferenca pode ser mensuravel em termos de pressao no GC e uso de memória.\nP: E possível ter uma função inline onde todas as lambdas sao noinline? R: Sim, o código compila, mas o compilador emite um warning indicando que não há beneficio em marcar a função como inline se nenhuma lambda e inlineada. A exceção e quando a função usa parametros de tipo reified, que exigem que a função seja inline.\nP: O noinline afeta o comportamento de return dentro da lambda? R: Sim. Uma lambda noinline se comporta como uma lambda normal: você só pode usar return qualificado (por exemplo, return@nomeDaFuncao), não return simples (non-local return). O return simples dentro de uma lambda noinline causa erro de compilação.\nErros comuns Usar noinline quando crossinline basta: se você só precisa impedir non-local return mas não precisa armazenar a lambda, crossinline e melhor porque mantém o beneficio de performance do inline.\nMarcar todas as lambdas como noinline: se todas as lambdas são noinline, não há motivo para a função ser inline. O compilador emite um warning nesses casos.\nEsquecer que noinline cria objeto: cada chamada com lambda noinline aloca um objeto Function. Em hot paths, isso pode importar.\nConfundir com o comportamento de funções normais: uma lambda noinline dentro de uma função inline se comporta exatamente como uma lambda em uma função normal \u0026ndash; sem non-local return e com alocacao de objeto.\nNao considerar reified: se a única razao para a função ser inline e usar reified, e todas as lambdas precisam ser noinline, reconsidere o design.\nTermos relacionados inline: modificador que copia o corpo da função e suas lambdas no local da chamada. crossinline: impede non-local return mas mantém o inline da lambda. Lambda: expressao funcional que pode ser passada como argumento. Higher-Order Function: função que recebe ou retorna lambdas, onde inline/noinline se aplicam. Reified: tipo generico materializado, disponivel apenas em funções inline. Function object: objeto criado para representar uma lambda quando ela não e inlineada. O noinline e uma ferramenta de precisao que permite controlar exatamente quais lambdas são inlineadas em uma função inline. Usado corretamente, ele da flexibilidade para armazenar e passar lambdas quando necessário, enquanto as outras lambdas da mesma função continuam aproveitando os beneficios de performance do inline.\n","permalink":"https://kotlin.dev.br/glossario/noinline/","summary":"\u003ch2 id=\"o-que-é-noinline-em-kotlin\"\u003eO que é noinline em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO modificador \u003cstrong\u003e\u003ccode\u003enoinline\u003c/code\u003e\u003c/strong\u003e é usado em parametros lambda de funções \u003ccode\u003einline\u003c/code\u003e para indicar que \u003cstrong\u003eaquela lambda específica não deve ser inlineada\u003c/strong\u003e. Quando uma função e marcada como \u003ccode\u003einline\u003c/code\u003e, por padrão todas as lambdas passadas a ela são copiadas no local da chamada. O \u003ccode\u003enoinline\u003c/code\u003e desativa esse comportamento para um parametro específico, tratando a lambda como um objeto \u003ccode\u003eFunction\u003c/code\u003e normal.\u003c/p\u003e\n\u003cp\u003eIsso e necessário quando você precisa armazenar a lambda em uma variavel, passa-la para outra função não-inline ou usa-la como referência.\u003c/p\u003e","title":"Noinline em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"Performance é um aspecto crítico em qualquer aplicação, seja um app Android que precisa manter 60 FPS ou um servidor backend processando milhares de requisicoes por segundo. Kotlin, rodando na JVM, herda tanto as otimizações poderosas do HotSpot quanto as armadilhas de performance comuns a linguagens JVM. Neste guia, vamos explorar tecnicas concretas para identificar gargalos, otimizar código Kotlin, configurar a JVM corretamente e aplicar padrões que fazem a diferenca em aplicações de producao. Cada dica vem com exemplos reais e mensuracoes para que você entenda o impacto de cada otimização.\nProfiling: Identificando Gargalos Antes de otimizar, e essencial medir. Otimizar sem dados e como atirar no escuro. As principais ferramentas de profiling para Kotlin são:\nO JVisualVM vem com o JDK e permite analisar uso de memória, threads e CPU em tempo real. O IntelliJ Profiler integra profiling diretamente na IDE, facilitando a correlacao com o código. O async-profiler é uma ferramenta de baixo overhead ideal para servidores em producao. O Android Profiler do Android Studio mostra CPU, memória, rede e energia em apps Android.\n// Medicao simples de tempo no codigo inline fun \u0026lt;T\u0026gt; measureTimeAndReturn( label: String, block: () -\u0026gt; T ): T { val inicio = System.nanoTime() val resultado = block() val duracao = (System.nanoTime() - inicio) / 1_000_000.0 println(\u0026#34;[$label] Executado em %.2f ms\u0026#34;.format(duracao)) return resultado } // Uso val produtos = measureTimeAndReturn(\u0026#34;Buscar produtos\u0026#34;) { repository.buscarTodos() } Coleções e Sequencias Uma das armadilhas mais comuns em Kotlin e o uso incorreto de operações encadeadas em coleções. Cada operação como map, filter e flatMap cria uma nova lista intermediaria:\n// Ineficiente: cria 3 listas intermediarias val resultado = produtos .filter { it.ativo } // Lista 1 .map { it.nome.uppercase() } // Lista 2 .sortedBy { it } // Lista 3 .take(10) // Lista 4 // Eficiente: usa Sequence (processamento lazy) val resultado = produtos.asSequence() .filter { it.ativo } .map { it.nome.uppercase() } .sortedBy { it } .take(10) .toList() // Materializa apenas no final Sequences processam elemento por elemento (pipeline vertical), evitando coleções intermediarias. A regra prática: use asSequence() quando tem 3 ou mais operações encadeadas ou quando a colecao e grande.\n// Benchmark comparativo fun benchmarkColecoes() { val lista = (1..1_000_000).toList() // Com listas: ~45ms, aloca ~3 listas de 1M elementos val r1 = measureTimeMillis { lista.filter { it % 2 == 0 }.map { it * 2 }.take(100) } // Com sequences: ~1ms, processa apenas 200 elementos val r2 = measureTimeMillis { lista.asSequence().filter { it % 2 == 0 }.map { it * 2 }.take(100).toList() } println(\u0026#34;Listas: ${r1}ms, Sequences: ${r2}ms\u0026#34;) } Inline Functions e Lambdas Cada lambda em Kotlin gera uma classe anonima na JVM, com custo de alocacao e invocacao. A keyword inline elimina esse custo:\n// Sem inline: gera objeto Function a cada chamada fun \u0026lt;T\u0026gt; executar(bloco: () -\u0026gt; T): T { return bloco() } // Com inline: o corpo da lambda e copiado no call site inline fun \u0026lt;T\u0026gt; executarInline(bloco: () -\u0026gt; T): T { return bloco() } // Inline e especialmente importante para funcoes de alta ordem chamadas frequentemente inline fun \u0026lt;T\u0026gt; List\u0026lt;T\u0026gt;.filterFast(predicate: (T) -\u0026gt; Boolean): List\u0026lt;T\u0026gt; { val resultado = ArrayList\u0026lt;T\u0026gt;(size / 2) for (item in this) { if (predicate(item)) { resultado.add(item) } } return resultado } As funções da stdlib como let, run, apply, also, map e filter já são inline, entao não há overhead ao usa-las.\nGerenciamento de Memória Evitando Alocacoes Desnecessarias // Ruim: cria novo objeto a cada chamada fun formatarPreco(valor: Double): String { val formatter = DecimalFormat(\u0026#34;#,##0.00\u0026#34;) return \u0026#34;R$ ${formatter.format(valor)}\u0026#34; } // Bom: reutiliza o formatter private val precoFormatter = DecimalFormat(\u0026#34;#,##0.00\u0026#34;) fun formatarPreco(valor: Double): String { return \u0026#34;R$ ${precoFormatter.format(valor)}\u0026#34; } // Ruim: boxing de primitivos val numeros: List\u0026lt;Int\u0026gt; = listOf(1, 2, 3) // Boxing Int -\u0026gt; Integer // Bom: usa IntArray para evitar boxing val numeros = intArrayOf(1, 2, 3) // Primitivos puros Value Classes para Zero-Cost Abstractions // Value class: zero overhead em runtime @JvmInline value class ClienteId(val valor: Long) @JvmInline value class Email(val valor: String) { init { require(valor.contains(\u0026#34;@\u0026#34;)) { \u0026#34;Email invalido\u0026#34; } } } @JvmInline value class Reais(val centavos: Long) { operator fun plus(outro: Reais) = Reais(centavos + outro.centavos) fun toDouble() = centavos / 100.0 } // Uso: type safety sem custo de alocacao fun buscarCliente(id: ClienteId): Cliente? { return repository.findById(id.valor) } Value classes são \u0026ldquo;desembrulhadas\u0026rdquo; em compilação, mantendo o tipo primitivo subjacente.\nCoroutines Eficientes // Ruim: cria coroutine para cada item sequencialmente suspend fun processarItens(itens: List\u0026lt;Item\u0026gt;) { for (item in itens) { launch { processar(item) }.join() // Espera cada um individualmente } } // Bom: paralelismo controlado suspend fun processarItens(itens: List\u0026lt;Item\u0026gt;) = coroutineScope { itens.map { item -\u0026gt; async(Dispatchers.Default) { processar(item) } }.awaitAll() } // Melhor: paralelismo limitado para nao sobrecarregar suspend fun processarItens(itens: List\u0026lt;Item\u0026gt;) { val semaforo = Semaphore(permits = 10) coroutineScope { itens.map { item -\u0026gt; async(Dispatchers.IO) { semaforo.withPermit { processar(item) } } }.awaitAll() } } Flow Otimizado // Ruim: buffer padrao pode causar backpressure val dados = flowDeDados() .collect { processar(it) } // Bom: buffer para desacoplar produtor e consumidor val dados = flowDeDados() .buffer(capacity = 64) .collect { processar(it) } // Conflated: descarta valores intermediarios se o consumidor e lento val sensorData = sensorFlow() .conflate() .collect { atualizarUI(it) } // Batch processing com chunked flowDeEventos() .chunked(100) .collect { lote -\u0026gt; repository.salvarEmLote(lote) } Otimização de String Operações com strings são surpreendentemente custosas:\n// Ruim: concatenacao em loop cria muitos objetos String fun construirRelatorio(itens: List\u0026lt;Item\u0026gt;): String { var resultado = \u0026#34;\u0026#34; for (item in itens) { resultado += \u0026#34;${item.nome}: ${item.valor}\\n\u0026#34; // Nova String a cada iteracao } return resultado } // Bom: StringBuilder fun construirRelatorio(itens: List\u0026lt;Item\u0026gt;): String { return buildString(itens.size * 50) { // Capacidade estimada for (item in itens) { append(item.nome) append(\u0026#34;: \u0026#34;) append(item.valor) appendLine() } } } // Bom: joinToString para casos simples fun construirRelatorio(itens: List\u0026lt;Item\u0026gt;): String { return itens.joinToString(\u0026#34;\\n\u0026#34;) { \u0026#34;${it.nome}: ${it.valor}\u0026#34; } } Configuração da JVM Parametros da JVM impactam diretamente a performance:\n// Parametros recomendados para servidores // -XX:+UseG1GC -\u0026gt; GC equilibrado para latencia e throughput // -XX:MaxRAMPercentage=75.0 -\u0026gt; Usa 75% da RAM disponivel // -XX:+UseContainerSupport -\u0026gt; Respeita limites de container // -XX:+ExitOnOutOfMemoryError -\u0026gt; Reinicia em OOM // -XX:+UseStringDeduplication -\u0026gt; Deduplica strings identicas no heap // -XX:+OptimizeStringConcat -\u0026gt; Otimiza concatenacao de strings // Para Android, use o Baseline Profile // Compila os caminhos mais comuns em AOT na instalacao @ExperimentalBaselineProfilesApi class BaselineProfileGenerator { @get:Rule val rule = BaselineProfileRule() @Test fun startup() { rule.collectBaselineProfile( packageName = \u0026#34;com.exemplo.app\u0026#34; ) { startActivityAndWait() } } } Cache Estrategico // Cache em memoria com LRU class LruCache\u0026lt;K, V\u0026gt;(private val maxSize: Int) { private val cache = LinkedHashMap\u0026lt;K, V\u0026gt;(maxSize, 0.75f, true) @Synchronized fun get(key: K): V? = cache[key] @Synchronized fun put(key: K, value: V) { cache[key] = value if (cache.size \u0026gt; maxSize) { val primeiraChave = cache.keys.first() cache.remove(primeiraChave) } } } // Cache com coroutines e expiracao class AsyncCache\u0026lt;K, V\u0026gt;( private val ttlMs: Long = 60_000L ) { private data class Entry\u0026lt;V\u0026gt;(val valor: V, val timestamp: Long) private val cache = ConcurrentHashMap\u0026lt;K, Entry\u0026lt;V\u0026gt;\u0026gt;() suspend fun getOrLoad(key: K, loader: suspend () -\u0026gt; V): V { val entry = cache[key] if (entry != null \u0026amp;\u0026amp; System.currentTimeMillis() - entry.timestamp \u0026lt; ttlMs) { return entry.valor } val valor = loader() cache[key] = Entry(valor, System.currentTimeMillis()) return valor } fun invalidar(key: K) { cache.remove(key) } } Boas Práticas de Performance em Kotlin Meça antes de otimizar: use profiler para identificar gargalos reais. Otimização prematura e a raiz de muitos problemas. Use Sequences para cadeias longas: a partir de 3 operações encadeadas em coleções grandes, Sequences fazem diferenca. Evite boxing desnecessário: use IntArray, LongArray em vez de List\u0026lt;Int\u0026gt; quando performance importa. Prefira value classes: para wrappers de primitivos, value classes eliminam alocacao em runtime. Reutilize objetos caros: formatters, regex compilados e conexoes de banco devem ser reutilizados. Configure o GC adequadamente: G1GC para servidores, ZGC para baixissima latencia. Use cache com sabedoria: cache acelera leituras mas adiciona complexidade de invalidacao. Erros Comuns e Armadilhas Otimizar sem medir: \u0026ldquo;acho que isso e lento\u0026rdquo; não e base para otimização. Sempre use dados de profiling. Ignorar alocacoes em loops: criar objetos dentro de loops executados milhoes de vezes e um gargalo clássico. Coroutines sem limite: lancar milhares de coroutines com Dispatchers.IO pode esgotar o pool de threads. Use semaforos. Cache sem invalidacao: dados cacheados desatualizados podem causar bugs sutis. Defina TTL ou invalidacao explicita. String concatenation em hotpath: em caminhos executados frequentemente, concatenacao cria pressao desnecessaria no GC. Regex não compilado: Regex compilado uma vez e reutilizado e ordens de magnitude mais rápido que compilar a cada uso. Conclusão e Próximos Passos Performance em Kotlin e um equilibrio entre código idiomatico e otimizações pontuais. A maioria do código deve priorizar legibilidade, e otimizações devem ser aplicadas apenas onde profiling indica necessidade real. As tecnicas apresentadas neste guia \u0026ndash; sequences, inline functions, value classes, cache e configuração da JVM \u0026ndash; cobrem os cenários mais comuns. Para ir além, explore ferramentas de APM como New Relic ou Datadog para monitoramento em producao e consulte nossos guias sobre Docker e microsserviços para otimizar a infraestrutura como um todo. Para uma perspectiva diferente sobre performance, veja como Rust alcança performance próxima ao C sem garbage collector e como Go equilibra simplicidade e performance no backend.\n","permalink":"https://kotlin.dev.br/guias/guia-kotlin-performance/","summary":"\u003cp\u003ePerformance é um aspecto crítico em qualquer aplicação, seja um app Android que precisa manter 60 FPS ou um servidor backend processando milhares de requisicoes por segundo. Kotlin, rodando na JVM, herda tanto as otimizações poderosas do HotSpot quanto as armadilhas de performance comuns a linguagens JVM. Neste guia, vamos explorar tecnicas concretas para identificar gargalos, otimizar código Kotlin, configurar a JVM corretamente e aplicar padrões que fazem a diferenca em aplicações de producao. Cada dica vem com exemplos reais e mensuracoes para que você entenda o impacto de cada otimização.\u003c/p\u003e","title":"Performance em Kotlin: Guia Completo de Otimização | Kotlin Brasil"},{"content":"O que é Modifier em Kotlin? Modifier é o mecanismo do Jetpack Compose para decorar, configurar e modificar componentes de UI. Ele controla aparencia (tamanho, padding, cor de fundo), comportamento (clique, scroll, foco) e layout (alinhamento, preenchimento, posicionamento) de qualquer Composable.\nEm vez de definir atributos em XML como no sistema antigo de Views, você encadeia chamadas de Modifier em uma sintaxe fluente e expressiva. A ordem das chamadas importa e afeta o resultado visual.\nSintaxe básica import androidx.compose.foundation.layout.* import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @Composable fun CartaoSimples() { Card( modifier = Modifier .fillMaxWidth() .padding(16.dp) ) { Text( text = \u0026#34;Conteudo do cartao\u0026#34;, modifier = Modifier.padding(24.dp) ) } } O Modifier começa como um objeto companheiro (singleton) e cada chamada retorna um novo Modifier com a modificacao aplicada. A cadeia e imutavel: cada passo cria um novo objeto.\nA ordem importa A ordem em que você encadeia modifiers afeta diretamente o resultado:\n// Padding ANTES do background: espaco transparente ao redor do fundo @Composable fun ExemploA() { Box( modifier = Modifier .padding(16.dp) .background(Color.Blue) .size(100.dp) ) } // Background ANTES do padding: fundo preenche o espaco do padding @Composable fun ExemploB() { Box( modifier = Modifier .background(Color.Blue) .padding(16.dp) .size(100.dp) ) } Pense nos modifiers como camadas aplicadas de fora para dentro. O primeiro modifier na cadeia e a camada mais externa.\nModifiers de tamanho @Composable fun ExemplosTamanho() { // Tamanho fixo Box(modifier = Modifier.size(100.dp)) // Largura e altura separadas Box(modifier = Modifier.width(200.dp).height(50.dp)) // Preencher todo o espaco disponivel Box(modifier = Modifier.fillMaxSize()) // Preencher apenas largura Box(modifier = Modifier.fillMaxWidth()) // Preencher uma fracao Box(modifier = Modifier.fillMaxWidth(0.5f)) // 50% da largura // Tamanho minimo e maximo Box(modifier = Modifier.widthIn(min = 100.dp, max = 300.dp)) // Tamanho baseado em aspecto Box(modifier = Modifier.aspectRatio(16f / 9f)) } Modifiers de aparencia @Composable fun ExemplosAparencia() { Box( modifier = Modifier .size(200.dp) .background( color = Color.Blue, shape = RoundedCornerShape(16.dp) ) .border( width = 2.dp, color = Color.DarkGray, shape = RoundedCornerShape(16.dp) ) .shadow( elevation = 8.dp, shape = RoundedCornerShape(16.dp) ) .alpha(0.9f) ) } Modifiers de interação @Composable fun ExemplosInteracao() { var clicado by remember { mutableStateOf(false) } Box( modifier = Modifier .clickable { clicado = !clicado } .combinedClickable( onClick = { /* clique simples */ }, onLongClick = { /* clique longo */ }, onDoubleClick = { /* clique duplo */ } ) ) // Scroll Column( modifier = Modifier.verticalScroll(rememberScrollState()) ) { // Conteudo scrollavel } // Arrastar Box( modifier = Modifier.draggable( orientation = Orientation.Horizontal, state = rememberDraggableState { delta -\u0026gt; // Processar delta do arrasto } ) ) } Criando Modifiers customizados Você pode criar extension functions em Modifier para reutilizar combinacoes:\nfun Modifier.cartaoPadrao(): Modifier = this .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 8.dp) .shadow(4.dp, RoundedCornerShape(12.dp)) .background(Color.White, RoundedCornerShape(12.dp)) .padding(16.dp) @Composable fun MeuCartao(titulo: String) { Column(modifier = Modifier.cartaoPadrao()) { Text(text = titulo) } } Para modifiers que dependem de estado do Compose, use composed:\nfun Modifier.shimmerEffect(): Modifier = composed { val transition = rememberInfiniteTransition() val alpha by transition.animateFloat( initialValue = 0.2f, targetValue = 1f, animationSpec = infiniteRepeatable( animation = tween(1000), repeatMode = RepeatMode.Reverse ) ) this.alpha(alpha) } Modifier como parametro O padrão recomendado e aceitar Modifier como parametro em Composables reutilizaveis:\n@Composable fun BotaoCustom( texto: String, onClick: () -\u0026gt; Unit, modifier: Modifier = Modifier // Valor padrao: Modifier vazio ) { Button( onClick = onClick, modifier = modifier .height(48.dp) .fillMaxWidth() ) { Text(text = texto) } } // Uso: o chamador pode adicionar modifiers extras @Composable fun Tela() { BotaoCustom( texto = \u0026#34;Salvar\u0026#34;, onClick = { /* ... */ }, modifier = Modifier.padding(16.dp) // Adicionado pelo chamador ) } O parametro modifier deve ser o primeiro parametro opcional e ter Modifier (vazio) como valor padrão. Isso segue as convenções da API do Compose.\nModifier.then para composição condicional @Composable fun ComponenteCondicional(habilitado: Boolean) { val modifierBase = Modifier.fillMaxWidth().padding(16.dp) val modifierFinal = if (habilitado) { modifierBase.then(Modifier.clickable { /* acao */ }) } else { modifierBase.then(Modifier.alpha(0.5f)) } Box(modifier = modifierFinal) { Text(\u0026#34;Conteudo\u0026#34;) } } Quando usar Modifier Sempre: praticamente todo Composable aceita e deveria aceitar um parametro Modifier. E a forma padrão de configurar aparencia e comportamento. Componentes reutilizaveis: sempre aceite modifier como parametro para permitir customizacao pelo chamador. Estilizacao consistente: crie extension functions de Modifier para padrões visuais reutilizaveis. Layout: Modifiers controlam como componentes se posicionam e ocupam espaco. Casos de Uso no Mundo Real Design systems corporativos: Empresas criam bibliotecas de Modifiers customizados que encapsulam padrões visuais do design system (espacamentos, bordas, sombras, cores). Isso garante consistencia visual em todas as telas da aplicação sem duplicar código de estilizacao.\nAcessibilidade em aplicações Android: Modifiers como semantics, contentDescription e testTag sao usados para tornar aplicações acessiveis a leitores de tela e para facilitar testes automatizados de UI. Equipes adicionam esses modifiers sistematicamente em componentes interativos.\nAnimacoes e transicoes de UI: Modifiers como animateContentSize, graphicsLayer e combinacoes com Modifier.offset sao usados para criar animacoes fluidas de entrada, saida e transicao entre estados de UI, como expandir/colapsar cards ou deslizar itens para deletar.\nLayouts responsivos para diferentes tamanhos de tela: Usando Modifier.fillMaxWidth(), widthIn() e aspectRatio() combinados com lógica condicional baseada no tamanho da janela, desenvolvedores criam layouts que se adaptam a celulares, tablets e desktops com Compose Multiplatform.\nBoas Praticas Sempre aceite Modifier como primeiro parametro opcional em Composables reutilizaveis, com valor padrão Modifier (vazio), seguindo as convencoes oficiais do Compose. Aplique o modifier recebido como parametro no elemento raiz do Composable antes de encadear seus próprios modifiers, para que o chamador tenha controle sobre o posicionamento e espaco externo. Crie extension functions de Modifier para combinacoes de estilos que se repetem no projeto, como Modifier.cartaoPadrao() ou Modifier.botaoDestaque(), promovendo reutilização e consistencia. Preste atencao na ordem de encadeamento: modifiers sao aplicados de fora para dentro. Coloque padding antes de background para criar espaco transparente ao redor, ou depois para criar padding interno colorido. Evite tamanhos fixos com Modifier.size() quando o componente precisa se adaptar a diferentes telas. Prefira combinacoes de fillMaxWidth(), widthIn() e heightIn() para layouts flexiveis. Perguntas Frequentes P: Por que a ordem dos Modifiers afeta o resultado visual? R: Modifiers sao aplicados sequencialmente como camadas de fora para dentro. Cada modifier envolve o anterior, alterando o espaco disponivel e a aparencia. Por exemplo, padding antes de background cria espaco transparente ao redor do fundo, enquanto background antes de padding faz com que a cor de fundo preencha também a area de padding.\nP: Qual a diferenca entre Modifier.then() e encadear modifiers diretamente? R: Encadear diretamente (.padding().background()) e o uso comum. Modifier.then() e útil para composicao condicional ou para combinar dois objetos Modifier separados em um só. Ambos produzem o mesmo resultado quando aplicados na mesma ordem.\nP: Como criar um Modifier que depende de estado do Compose? R: Use a função composed {} para criar modifiers que precisam de estado do Compose, como remember ou animateFloat. Dentro do bloco composed, você tem acesso ao contexto de composicao e pode usar hooks normalmente.\nP: O Modifier afeta a performance de recomposicao? R: Modifiers sao objetos imutaveis e o Compose os compara eficientemente durante a recomposicao. Porem, criar modifiers dentro de lambdas sem remember pode causar realocacoes desnecessarias. Para modifiers estaticos, defina-os fora da função Composable ou use remember para memoiza-los.\nErros comuns Ignorar a ordem dos modifiers: padding antes de background e diferente de background antes de padding. Sempre teste visualmente com @Preview.\nNao aceitar Modifier como parametro: componentes que não aceitam Modifier não podem ser estilizados externamente, reduzindo a reutilização.\nUsar Modifier.size fixo em excesso: tamanhos fixos não se adaptam a diferentes telas. Prefira fillMaxWidth com padding ou widthIn com limites.\nCriar modifiers dentro de lambdas de recomposicao: se um modifier e criado com composed ou remember, certifique-se de que não esta sendo recriado desnecessariamente.\nNao encadear com o modifier recebido: quando você recebe modifier como parametro, aplique-o no elemento raiz antes de adicionar seus próprios modifiers.\nTermos relacionados Composable: função anotada com @Composable que descreve UI e aceita Modifiers. State: estado reativo que pode ser usado em conjunto com modifiers condicionais. Layout: sistema de posicionamento do Compose onde Modifiers influenciam tamanho e posicao. padding/size/fillMaxWidth: funções de extensao de Modifier para configurar dimensoes. clickable: modifier de interação que torna componentes clicaveis. Recomposicao: processo que reaplica modifiers quando o estado muda. Modifier e o canivete suico do Jetpack Compose. Dominar a encadeamento de modifiers, entender a importancia da ordem e criar modifiers customizados reutilizaveis são habilidades fundamentais para construir interfaces bonitas e funcionais em Kotlin.\n","permalink":"https://kotlin.dev.br/glossario/modifier/","summary":"\u003ch2 id=\"o-que-é-modifier-em-kotlin\"\u003eO que é Modifier em Kotlin?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eModifier\u003c/strong\u003e é o mecanismo do Jetpack Compose para \u003cstrong\u003edecorar, configurar e modificar\u003c/strong\u003e componentes de UI. Ele controla aparencia (tamanho, padding, cor de fundo), comportamento (clique, scroll, foco) e layout (alinhamento, preenchimento, posicionamento) de qualquer Composable.\u003c/p\u003e\n\u003cp\u003eEm vez de definir atributos em XML como no sistema antigo de Views, você encadeia chamadas de Modifier em uma sintaxe fluente e expressiva. A ordem das chamadas importa e afeta o resultado visual.\u003c/p\u003e","title":"Modifier em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Type Alias em Kotlin? Um type alias em Kotlin é um nome alternativo para um tipo existente. Ele não cria um novo tipo, mas oferece uma forma mais legivel de referenciar tipos complexos ou longos. Declarado com a palavra-chave typealias, esse recurso melhora a legibilidade do código sem impacto em performance, pois o compilador substitui o alias pelo tipo original durante a compilação.\nType aliases são especialmente úteis quando você trabalha com tipos genericos compostos, funções de ordem superior com assinaturas longas ou tipos de plataformas externas que possuem nomes pouco descritivos.\nSintaxe básica A declaracao de um type alias e feita no nível do arquivo (top-level), fora de classes ou funções:\ntypealias ListaDeUsuarios = List\u0026lt;Usuario\u0026gt; typealias Callback\u0026lt;T\u0026gt; = (T) -\u0026gt; Unit typealias MapaDeNotas = Map\u0026lt;String, List\u0026lt;Double\u0026gt;\u0026gt; Apos a declaracao, você pode usar o alias em qualquer lugar onde usaria o tipo original:\ndata class Usuario(val nome: String, val idade: Int) typealias ListaDeUsuarios = List\u0026lt;Usuario\u0026gt; fun exibirUsuarios(usuarios: ListaDeUsuarios) { usuarios.forEach { println(\u0026#34;${it.nome} - ${it.idade} anos\u0026#34;) } } fun main() { val lista: ListaDeUsuarios = listOf( Usuario(\u0026#34;Ana\u0026#34;, 28), Usuario(\u0026#34;Carlos\u0026#34;, 35) ) exibirUsuarios(lista) } Exemplos práticos Simplificando tipos de função Tipos de função em Kotlin podem ficar extensos quando possuem vários parametros. Type aliases resolvem isso:\ntypealias Validador\u0026lt;T\u0026gt; = (T) -\u0026gt; Boolean typealias Transformador\u0026lt;T, R\u0026gt; = (T) -\u0026gt; R typealias GerenciadorDeErro = (Exception) -\u0026gt; Unit fun \u0026lt;T\u0026gt; filtrar(lista: List\u0026lt;T\u0026gt;, validador: Validador\u0026lt;T\u0026gt;): List\u0026lt;T\u0026gt; { return lista.filter(validador) } fun \u0026lt;T, R\u0026gt; mapear(lista: List\u0026lt;T\u0026gt;, transformador: Transformador\u0026lt;T, R\u0026gt;): List\u0026lt;R\u0026gt; { return lista.map(transformador) } fun executarComTratamento(bloco: () -\u0026gt; Unit, onErro: GerenciadorDeErro) { try { bloco() } catch (e: Exception) { onErro(e) } } fun main() { val numeros = listOf(1, 2, 3, 4, 5, 6) val pares = filtrar(numeros) { it % 2 == 0 } println(pares) // [2, 4, 6] val textos = mapear(numeros) { \u0026#34;Numero $it\u0026#34; } println(textos) // [Numero 1, Numero 2, ...] executarComTratamento( bloco = { println(\u0026#34;Executando operacao\u0026#34;) }, onErro = { println(\u0026#34;Erro: ${it.message}\u0026#34;) } ) } Trabalhando com tipos genericos complexos typealias ResultadoApi\u0026lt;T\u0026gt; = Pair\u0026lt;Int, T?\u0026gt; typealias TabelaDePrecos = Map\u0026lt;String, Map\u0026lt;String, Double\u0026gt;\u0026gt; typealias MatrizInteira = Array\u0026lt;IntArray\u0026gt; fun buscarUsuario(id: Int): ResultadoApi\u0026lt;Usuario\u0026gt; { return if (id \u0026gt; 0) { 200 to Usuario(\u0026#34;Ana\u0026#34;, 28) } else { 404 to null } } fun criarTabelaPrecos(): TabelaDePrecos { return mapOf( \u0026#34;eletronicos\u0026#34; to mapOf( \u0026#34;notebook\u0026#34; to 4500.00, \u0026#34;smartphone\u0026#34; to 2800.00 ), \u0026#34;livros\u0026#34; to mapOf( \u0026#34;kotlin-em-acao\u0026#34; to 89.90, \u0026#34;clean-code\u0026#34; to 75.00 ) ) } fun criarMatriz(linhas: Int, colunas: Int): MatrizInteira { return Array(linhas) { IntArray(colunas) } } Type alias para inner classes e nested classes class Repositorio { sealed class Resultado\u0026lt;out T\u0026gt; { data class Sucesso\u0026lt;T\u0026gt;(val dados: T) : Resultado\u0026lt;T\u0026gt;() data class Erro(val mensagem: String) : Resultado\u0026lt;Nothing\u0026gt;() data object Carregando : Resultado\u0026lt;Nothing\u0026gt;() } } // Sem alias: Repositorio.Resultado.Sucesso\u0026lt;Usuario\u0026gt; // Com alias: typealias RepoResultado\u0026lt;T\u0026gt; = Repositorio.Resultado\u0026lt;T\u0026gt; typealias RepoSucesso\u0026lt;T\u0026gt; = Repositorio.Resultado.Sucesso\u0026lt;T\u0026gt; typealias RepoErro = Repositorio.Resultado.Erro fun buscarDados(): RepoResultado\u0026lt;String\u0026gt; { return RepoSucesso(\u0026#34;Dados carregados\u0026#34;) } fun main() { when (val resultado = buscarDados()) { is RepoSucesso -\u0026gt; println(resultado.dados) is RepoErro -\u0026gt; println(resultado.mensagem) is Repositorio.Resultado.Carregando -\u0026gt; println(\u0026#34;Carregando...\u0026#34;) } } Type alias com tipos de plataforma Quando você integra Kotlin com bibliotecas Java ou APIs externas, os nomes de tipos podem ser longos e pouco descritivos:\nimport java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ScheduledExecutorService typealias CacheDeTokens = ConcurrentHashMap\u0026lt;String, Pair\u0026lt;String, Long\u0026gt;\u0026gt; typealias Agendador = ScheduledExecutorService class GerenciadorDeTokens( private val cache: CacheDeTokens = CacheDeTokens(), private val agendador: Agendador ) { fun armazenar(chave: String, token: String, expiracao: Long) { cache[chave] = token to expiracao } fun obter(chave: String): String? { val entrada = cache[chave] ?: return null return if (System.currentTimeMillis() \u0026lt; entrada.second) entrada.first else null } } Quando usar type alias Type aliases são mais úteis nos seguintes cenários:\nTipos genericos profundamente aninhados como Map\u0026lt;String, List\u0026lt;Pair\u0026lt;Int, Double\u0026gt;\u0026gt;\u0026gt; que aparecem em vários pontos do código. Assinaturas de função repetitivas quando um mesmo tipo de callback e usado em múltiplas funções. Nomes de dominio mais expressivos para tornar o código mais legivel no contexto do negócio, como typealias CPF = String ou typealias Reais = Double. Encurtar referências a classes internas de bibliotecas ou de seus próprios modulos. Migração gradual quando você quer renomear um tipo sem alterar todo o código de uma vez. Casos de Uso no Mundo Real Camadas de repositório e servico: em projetos com arquitetura em camadas, type aliases simplificam tipos de retorno complexos como Flow\u0026lt;Result\u0026lt;List\u0026lt;Usuario\u0026gt;\u0026gt;\u0026gt; ou suspend () -\u0026gt; Result\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt;. Isso torna as assinaturas de funções dos repositórios mais legiveis e consistentes em toda a base de código.\nCallbacks em SDKs e bibliotecas: bibliotecas que expõe APIs com callbacks usam type aliases para dar nomes semanticos aos tipos de função. Por exemplo, typealias OnItemClick\u0026lt;T\u0026gt; = (T, Int) -\u0026gt; Unit e mais expressivo do que repetir a assinatura completa em cada função publica da API.\nMapeamento de entidades entre camadas: projetos que seguem Clean Architecture frequentemente definem aliases para mapear entre tipos de diferentes camadas, como typealias EntityMapper\u0026lt;Domain, Data\u0026gt; = (Data) -\u0026gt; Domain, criando uma convencao clara para todas as funções de mapeamento.\nintegração com bibliotecas Java: ao usar bibliotecas Java que possuem tipos com nomes longos ou pouco descritivos (como ConcurrentHashMap\u0026lt;String, List\u0026lt;WeakReference\u0026lt;Callback\u0026gt;\u0026gt;\u0026gt;\u0026gt;), type aliases permitem criar nomes mais concisos e contextualizados no dominio do projeto Kotlin.\nBoas Praticas Use type aliases apenas quando o tipo original aparece em múltiplos lugares e sua complexidade prejudica a leitura. Criar aliases para tipos simples como String ou Int raramente agrega valor. Escolha nomes que reflitam o dominio do negócio, não a estrutura tecnica. Prefira typealias TabelaDePrecos = Map\u0026lt;String, Double\u0026gt; em vez de typealias StringDoubleMap = Map\u0026lt;String, Double\u0026gt;. Quando precisar de seguranca de tipos real (impedir que um CPF seja usado onde se espera um Email), use value classes em vez de type aliases. O alias e apenas um apelido e não impede substituicoes indevidas. Declare todos os type aliases no nivel do arquivo (top-level), preferencialmente agrupados em um arquivo dedicado como TypeAliases.kt ou proximo aos tipos que eles referenciam, facilitando a descoberta. Evite criar aliases para tipos que já sao claros no contexto. O excesso de aliases pode dificultar a navegação no código e confundir desenvolvedores que precisam descobrir o tipo real por tras do alias. Perguntas Frequentes P: Type alias cria um novo tipo ou apenas um apelido? R: Apenas um apelido. O compilador substitui o alias pelo tipo original durante a compilação. Isso significa que typealias CPF = String permite usar um CPF em qualquer lugar que aceite String e vice-versa. Nao há verificação de tipo adicional em tempo de compilação.\nP: Posso declarar um type alias dentro de uma classe ou função? R: Nao. Type aliases em Kotlin só podem ser declarados no nivel do arquivo (top-level). Tentar declarar dentro de uma classe, objeto ou função resulta em erro de compilação. Essa restricao existe porque aliases sao resolvidos em tempo de compilação e precisam ter escopo global.\nP: Type alias tem algum impacto em performance? R: Nenhum. O alias e completamente eliminado durante a compilação. No bytecode final, apenas o tipo original aparece. Nao há alocacao extra, indireção ou qualquer custo em tempo de execução.\nP: Quando devo usar type alias em vez de value class? R: Use type alias quando o objetivo e apenas melhorar a legibilidade de tipos complexos sem necessidade de seguranca de tipos adicional. Use value class quando você precisa que o compilador impeca a troca acidental de valores com o mesmo tipo subjacente, como evitar que um UserId seja passado onde se espera um ProductId.\nErros comuns Confundir type alias com novo tipo typealias CPF = String typealias Email = String fun enviarPara(email: Email) { println(\u0026#34;Enviando para $email\u0026#34;) } fun main() { val cpf: CPF = \u0026#34;123.456.789-00\u0026#34; enviarPara(cpf) // Compila sem erro! CPF e Email são ambos String } O type alias não cria um novo tipo. CPF e Email são intercambiaveis porque ambos são String. Se você precisa de segurança de tipos, use value classes (inline classes) em vez de type aliases.\nDeclarar dentro de funções ou classes // ERRADO: type alias nao pode ser local fun processar() { typealias Dados = List\u0026lt;String\u0026gt; // erro de compilacao } // CORRETO: declarar no nível do arquivo typealias Dados = List\u0026lt;String\u0026gt; fun processar(dados: Dados) { /* ... */ } Alias para tipos com variancia conflitante open class Animal class Cachorro : Animal() typealias ListaAnimais = MutableList\u0026lt;Animal\u0026gt; fun main() { val cachorros: MutableList\u0026lt;Cachorro\u0026gt; = mutableListOf(Cachorro()) // val animais: ListaAnimais = cachorros // Erro: tipos incompativeis // MutableList\u0026lt;Cachorro\u0026gt; nao e subtipo de MutableList\u0026lt;Animal\u0026gt; } O alias não altera as regras de variancia do tipo original. MutableList e invariante, entao MutableList\u0026lt;Cachorro\u0026gt; não e subtipo de MutableList\u0026lt;Animal\u0026gt;, independentemente do alias.\nExcesso de aliases Criar aliases demais pode dificultar a navegação no código. Se o tipo original já e claro, o alias adiciona uma camada desnecessaria de indirecao. Use com moderacao.\nTermos relacionados Value class (inline class): cria um tipo wrapper com segurança de tipos em tempo de compilação, diferente do type alias que e apenas um apelido. Generics: sistema de tipos parametrizados que frequentemente gera tipos longos beneficiados por aliases. Função de ordem superior: funções que recebem ou retornam outras funções, cujas assinaturas são frequentemente simplificadas com aliases. Data class: tipo de classe em Kotlin para armazenar dados, frequentemente referenciada por aliases quando usada em coleções. Sealed class: hierarquia restrita de tipos que pode ter aliases para facilitar a referência a subtipos. Conclusão Type aliases são uma ferramenta simples mas eficaz para melhorar a legibilidade do código Kotlin. Eles não criam novos tipos nem adicionam overhead em tempo de execução. Use-os para simplificar tipos genericos complexos, assinaturas de função longas e referências a classes profundamente aninhadas. Quando precisar de segurança de tipos real, considere value classes como alternativa. O equiibrio entre legibilidade e clareza e a chave para usar type aliases de forma produtiva.\n","permalink":"https://kotlin.dev.br/glossario/type-alias/","summary":"\u003ch2 id=\"o-que-é-type-alias-em-kotlin\"\u003eO que é Type Alias em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUm type alias em Kotlin é um nome alternativo para um tipo existente. Ele não cria um novo tipo, mas oferece uma forma mais legivel de referenciar tipos complexos ou longos. Declarado com a palavra-chave \u003ccode\u003etypealias\u003c/code\u003e, esse recurso melhora a legibilidade do código sem impacto em performance, pois o compilador substitui o alias pelo tipo original durante a compilação.\u003c/p\u003e\n\u003cp\u003eType aliases são especialmente úteis quando você trabalha com tipos genericos compostos, funções de ordem superior com assinaturas longas ou tipos de plataformas externas que possuem nomes pouco descritivos.\u003c/p\u003e","title":"Type Alias em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é lateinit em Kotlin? O modificador lateinit permite declarar uma propriedade var não-nullable sem inicializa-la no momento da declaracao. Você esta dizendo ao compilador: \u0026ldquo;eu garanto que vou inicializar essa propriedade antes de usa-la\u0026rdquo;. Isso e útil quando a inicialização depende de um framework (como injeção de dependências) ou acontece em um método de ciclo de vida.\nSem lateinit, toda propriedade não-nullable precisa ser inicializada no construtor ou na declaracao. Com lateinit, você adia essa inicialização para um momento posterior.\nSintaxe básica class MinhaActivity { lateinit var repositorio: Repositorio fun onCreate() { repositorio = Repositorio() // Inicializada depois da construcao repositorio.carregar() } } Sem lateinit, você teria que usar nullable (Repositorio?) e lidar com verificacoes de null em todo lugar, ou inicializar com um valor dummy que não faz sentido.\nRegras do lateinit O lateinit tem restricoes específicas:\nclass Exemplo { // OK: var + tipo nao-nullable + nao-primitivo lateinit var nome: String // ERRO: val nao pode ser lateinit (precisa ser var) // lateinit val constante: String // ERRO: tipos primitivos nao podem ser lateinit // lateinit var contador: Int // ERRO: tipo nullable nao faz sentido com lateinit // lateinit var opcional: String? } Resumo das regras:\nDeve ser var (não val). Deve ser tipo não-nullable. Nao pode ser tipo primitivo (Int, Long, Boolean, etc.). Nao pode ter getter ou setter customizado. Pode ser usada em propriedades de classe ou top-level. Verificando inicialização com isInitialized A partir do Kotlin 1.2, você pode verificar se uma propriedade lateinit já foi inicializada:\nclass Serviço { lateinit var conexao: Conexao fun verificar() { if (::conexao.isInitialized) { println(\u0026#34;Conexao ativa: $conexao\u0026#34;) } else { println(\u0026#34;Conexao ainda nao foi estabelecida\u0026#34;) } } fun desconectar() { if (::conexao.isInitialized) { conexao.fechar() } } } A sintaxe ::propriedade.isInitialized usa referência de propriedade. Isso e útil em métodos de limpeza ou quando a inicialização e condicional.\nlateinit em Android O caso de uso mais clássico de lateinit e em Activities e Fragments do Android:\nclass UsuarioActivity : AppCompatActivity() { lateinit var binding: ActivityUsuarioBinding lateinit var viewModel: UsuarioViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityUsuarioBinding.inflate(layoutInflater) setContentView(binding.root) viewModel = ViewModelProvider(this)[UsuarioViewModel::class.java] configurarUI() } private fun configurarUI() { binding.botaoSalvar.setOnClickListener { viewModel.salvar() } } } Aqui, binding e viewModel não podem ser inicializados no construtor porque dependem do ciclo de vida da Activity. O lateinit e a solução natural.\nlateinit com injeção de dependências Frameworks como Dagger, Hilt e Koin frequentemente usam lateinit para injeção:\nclass MeuServico { @Inject lateinit var repositorio: Repositorio @Inject lateinit var logger: Logger fun executar() { logger.info(\u0026#34;Executando...\u0026#34;) repositorio.processar() } } O framework de DI preenche as propriedades apos a construcao do objeto, antes de qualquer método de negócio ser chamado.\nlateinit vs lazy Ambos adiam a inicialização, mas de formas diferentes:\nclass Comparação { // lateinit: inicializacao explicita, var, mutavel lateinit var valorLateInit: String // lazy: inicializacao automatica na primeira leitura, val, imutavel val valorLazy: String by lazy { println(\u0026#34;Inicializando lazy...\u0026#34;) \u0026#34;Valor calculado\u0026#34; } fun inicializar() { valorLateInit = \u0026#34;Valor definido\u0026#34; } } fun main() { val obj = Comparação() // lazy: inicializa automaticamente na primeira leitura println(obj.valorLazy) // Imprime \u0026#34;Inicializando lazy...\u0026#34; e \u0026#34;Valor calculado\u0026#34; // lateinit: voce controla quando inicializar obj.inicializar() println(obj.valorLateInit) } Quando usar cada um:\nlateinit: quando a inicialização depende de um fator externo (DI, ciclo de vida, framework). lazy: quando o valor pode ser calculado a partir de informações já disponiveis, mas você quer adiar o calculo. O que acontece se acessar antes de inicializar class Perigo { lateinit var dados: String fun acessar() { println(dados) // UninitializedPropertyAccessException! } } fun main() { val obj = Perigo() obj.acessar() // kotlin.UninitializedPropertyAccessException: // lateinit property dados has not been initialized } A exceção UninitializedPropertyAccessException e lancada com uma mensagem clara indicando qual propriedade não foi inicializada. E mais informativa que um NullPointerException.\nlateinit em testes lateinit e muito comum em classes de teste:\nclass CalculadoraTest { lateinit var calculadora: Calculadora lateinit var logger: MockLogger @BeforeEach fun setup() { logger = MockLogger() calculadora = Calculadora(logger) } @Test fun `soma dois numeros`() { val resultado = calculadora.somar(2, 3) assertEquals(5, resultado) } @Test fun `registra operacao no log`() { calculadora.somar(2, 3) assertTrue(logger.mensagens.contains(\u0026#34;Soma: 2 + 3 = 5\u0026#34;)) } } O método @BeforeEach inicializa as propriedades antes de cada teste, garantindo um estado limpo.\nQuando usar lateinit Injeção de dependências: quando frameworks preenchem propriedades apos a construcao. Ciclo de vida: em Android, quando propriedades dependem de onCreate ou onViewCreated. Testes: para inicializar objetos em métodos @BeforeEach ou @Before. Configuração tardia: quando a inicialização depende de dados que chegam depois da construcao. Casos de Uso no Mundo Real Activities e Fragments no Android: O caso mais comum de lateinit e para propriedades como binding e viewModel em Activities e Fragments, que só podem ser inicializadas nos métodos de ciclo de vida (onCreate, onViewCreated). Sem lateinit, seria necessário declarar essas propriedades como nullable e adicionar verificacoes de null em cada acesso.\nInjecao de dependências com Dagger/Hilt: Frameworks de DI baseados em field injection usam lateinit extensivamente. O framework injeta as dependências apos a construcao do objeto, e o lateinit permite que essas propriedades sejam declaradas como não-nullable, simplificando todo o código que as utiliza.\nconfiguração de testes unitarios: Em classes de teste, objetos como mocks, stubs e o próprio sistema sendo testado sao inicializados em métodos @BeforeEach ou @Before. O lateinit permite declarar esses objetos no nivel da classe sem precisar inicializa-los com valores placeholder.\nPlugins e sistemas de modulos: Em arquiteturas de plugins onde componentes sao registrados e inicializados em fases distintas, lateinit permite declarar dependências entre modulos que serao resolvidas durante a fase de inicialização do sistema.\nBoas Praticas Use lateinit apenas quando a inicialização realmente não pode acontecer no construtor. Se o valor pode ser calculado a partir de dados já disponiveis, prefira lazy. Sempre verifique ::propriedade.isInitialized em métodos de limpeza e destruicao (como onDestroy) antes de acessar propriedades lateinit, pois o método de inicialização pode não ter sido chamado. Evite usar lateinit como mecanismo para contornar o sistema de null safety do Kotlin. Se a propriedade pode legitimamente não ter valor, use um tipo nullable. Documente claramente qual método ou fase do ciclo de vida e responsavel por inicializar cada propriedade lateinit, para que outros desenvolvedores saibam onde procurar a inicialização. Prefira constructor injection sobre field injection com lateinit sempre que possível, pois o construtor garante que todas as dependências estejam presentes no momento da criação do objeto. Perguntas Frequentes P: Por que lateinit não funciona com tipos primitivos como Int e Boolean? R: Internamente, lateinit usa null como sentinela para detectar se a propriedade foi inicializada. Tipos primitivos na JVM não podem ser null, entao o Kotlin não conseguiria distinguir entre \u0026ldquo;não inicializado\u0026rdquo; e um valor válido como 0 ou false. Para primitivos, use Delegates.notNull() como alternativa.\nP: Qual a diferenca entre lateinit e declarar a propriedade como nullable? R: Com lateinit, a propriedade e não-nullable e você acessa diretamente sem operadores ?. ou !!. Se acessada antes da inicialização, uma UninitializedPropertyAccessException e lancada com uma mensagem clara. Com nullable, você precisa de verificacoes de null em cada acesso, mas tem a flexibilidade de representar a ausência de valor como parte do dominio.\nP: Posso usar lateinit com val? R: Nao. O lateinit requer var porque a propriedade precisa ser atribuida apos a construcao do objeto. Para inicialização tardia com val, use o delegate by lazy, que calcula o valor na primeira leitura e o armazena de forma imutavel.\nP: O lateinit tem custo de performance? R: O custo e negligivel. Internamente, o Kotlin gera uma verificação de null no getter da propriedade. Se o valor for null (não inicializado), a exceção e lancada. Essa verificação e comparavel ao custo de um acesso nullable com !!.\nErros comuns Acessar antes de inicializar: o erro mais obvio. Sempre garanta que a propriedade e inicializada antes do primeiro acesso. Use isInitialized quando houver duvida.\nUsar lateinit quando lazy e melhor: se o valor pode ser calculado a partir de dados já disponiveis, lazy e mais seguro porque e automatico e imutavel.\nUsar lateinit para contornar null safety: declarar lateinit só para evitar ? e verificacoes de null e um mau uso. Se o valor pode legitimamente ser null, use String?.\nLateinit em propriedades que nunca são reinicializadas: se a propriedade e definida uma única vez e nunca muda, considere lazy com val para garantir imutabilidade.\nNao tratar o caso de não-inicialização em cleanup: em métodos como onDestroy, verificar isInitialized antes de acessar propriedades que podem não ter sido inicializadas (ex: se onCreate falhou).\nTermos relacionados val: variavel somente leitura que não pode ser usada com lateinit. var: variavel mutavel, requisito para lateinit. lazy: delegação de propriedade que inicializa na primeira leitura, alternativa ao lateinit. Nullable: tipos que aceitam null (String?), alternativa ao lateinit quando null e um estado válido. Property Delegate: mecanismo que lazy usa internamente, permitindo lógica customizada de leitura e escrita. Dependency Injection: padrão de design onde lateinit e frequentemente usado para receber dependências. O lateinit e uma ferramenta pragmatica que resolve situacoes reais onde a inicialização no construtor não e possível. Usado com disciplina, ele mantém o código limpo e livre de verificacoes de null desnecessarias, enquanto a verificação em tempo de execução garante que erros de inicialização sejam detectados cedo com mensagens claras.\n","permalink":"https://kotlin.dev.br/glossario/lateinit/","summary":"\u003ch2 id=\"o-que-é-lateinit-em-kotlin\"\u003eO que é lateinit em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO modificador \u003cstrong\u003e\u003ccode\u003elateinit\u003c/code\u003e\u003c/strong\u003e permite declarar uma propriedade \u003ccode\u003evar\u003c/code\u003e não-nullable \u003cstrong\u003esem inicializa-la no momento da declaracao\u003c/strong\u003e. Você esta dizendo ao compilador: \u0026ldquo;eu garanto que vou inicializar essa propriedade antes de usa-la\u0026rdquo;. Isso e útil quando a inicialização depende de um framework (como injeção de dependências) ou acontece em um método de ciclo de vida.\u003c/p\u003e\n\u003cp\u003eSem \u003ccode\u003elateinit\u003c/code\u003e, toda propriedade não-nullable precisa ser inicializada no construtor ou na declaracao. Com \u003ccode\u003elateinit\u003c/code\u003e, você adia essa inicialização para um momento posterior.\u003c/p\u003e","title":"Lateinit em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"DevOps e CI/CD não são mais diferenciais, são requisitos básicos em projetos profissionais. Para projetos Kotlin, montar pipelines de integração e entrega contínua garante qualidade, velocidade e confiança em cada deploy. Neste artigo, vamos explorar como configurar CI/CD eficaz para projetos Kotlin.\nO que é CI/CD e por que importa CI (Continuous Integration) é a prática de integrar código frequentemente, com verificações automáticas a cada push. CD (Continuous Delivery/Deployment) automatiza o processo de levar o código para produção.\nPara projetos Kotlin, isso significa:\nCompilar e testar automaticamente a cada commit Verificar qualidade de código com análise estática Gerar artefatos (JARs, APKs, imagens Docker) automaticamente Fazer deploy em ambientes de staging e produção Estrutura de Pipeline para Kotlin Um pipeline típico para um projeto Kotlin backend tem as seguintes etapas:\n1. Build e Compilação // build.gradle.kts - Configuração otimizada para CI plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.1.0\u0026#34; kotlin(\u0026#34;plugin.spring\u0026#34;) version \u0026#34;2.1.0\u0026#34; id(\u0026#34;org.springframework.boot\u0026#34;) version \u0026#34;3.3.0\u0026#34; id(\u0026#34;io.spring.dependency-management\u0026#34;) version \u0026#34;1.1.4\u0026#34; id(\u0026#34;org.jetbrains.kotlinx.kover\u0026#34;) version \u0026#34;0.7.5\u0026#34; // Cobertura de código id(\u0026#34;io.gitlab.arturbosch.detekt\u0026#34;) version \u0026#34;1.23.4\u0026#34; // Análise estática } detekt { config.setFrom(files(\u0026#34;config/detekt/detekt.yml\u0026#34;)) buildUponDefaultConfig = true allRules = false } kover { reports { filters { excludes { classes(\u0026#34;*.config.*\u0026#34;, \u0026#34;*.Application*\u0026#34;) } } verify { rule { minBound(80) // Mínimo 80% de cobertura } } } } 2. Testes Automatizados // Testes bem estruturados são a base do CI @SpringBootTest class PedidoServiceIntegrationTest { @Autowired private lateinit var pedidoService: PedidoService @Autowired private lateinit var pedidoRepository: PedidoRepository @Test fun `deve criar pedido e persistir no banco`() = runTest { // Given val request = CriarPedidoRequest( clienteId = \u0026#34;cliente-1\u0026#34;, itens = listOf( ItemRequest(produtoId = \u0026#34;prod-1\u0026#34;, quantidade = 2), ItemRequest(produtoId = \u0026#34;prod-2\u0026#34;, quantidade = 1) ) ) // When val pedido = pedidoService.criarPedido(request) // Then assertThat(pedido.id).isNotNull() assertThat(pedido.status).isEqualTo(PedidoStatus.CRIADO) val persistido = pedidoRepository.findById(pedido.id) assertThat(persistido).isNotNull() assertThat(persistido!!.itens).hasSize(2) } @AfterEach fun cleanup() = runBlocking { pedidoRepository.deleteAll() } } 3. Análise Estática com Detekt Detekt é a ferramenta padrão para análise estática de código Kotlin:\n// config/detekt/detekt.yml (em formato YAML, referenciado pelo Gradle) // Configurações típicas incluem: // - Complexidade ciclomática máxima // - Tamanho máximo de funções // - Detecção de code smells // - Regras de formatação // Exemplo de código que detekt flagraria: // RUIM - Função muito complexa fun processarDados(dados: List\u0026lt;Any\u0026gt;): String { // detekt avisaria sobre complexidade excessiva var resultado = \u0026#34;\u0026#34; for (dado in dados) { when (dado) { is String -\u0026gt; resultado += dado.uppercase() is Int -\u0026gt; resultado += dado.toString() is List\u0026lt;*\u0026gt; -\u0026gt; resultado += dado.size.toString() else -\u0026gt; resultado += \u0026#34;unknown\u0026#34; } } return resultado } // BOM - Função simples e clara fun processarDados(dados: List\u0026lt;Any\u0026gt;): String { return dados.joinToString(\u0026#34;\u0026#34;) { dado -\u0026gt; formatarDado(dado) } } private fun formatarDado(dado: Any): String = when (dado) { is String -\u0026gt; dado.uppercase() is Int -\u0026gt; dado.toString() is List\u0026lt;*\u0026gt; -\u0026gt; dado.size.toString() else -\u0026gt; \u0026#34;unknown\u0026#34; } 4. Build de Imagem Docker // Dockerfile para aplicacao Kotlin/Spring Boot // Multi-stage build para imagem otimizada // Usando Gradle para build // Stage 1: Build // FROM gradle:8.5-jdk21 AS build // COPY . /app // WORKDIR /app // RUN gradle bootJar --no-daemon // Stage 2: Runtime // FROM eclipse-temurin:21-jre-alpine // COPY --from=build /app/build/libs/*.jar app.jar // EXPOSE 8080 // ENTRYPOINT [\u0026#34;java\u0026#34;, \u0026#34;-jar\u0026#34;, \u0026#34;app.jar\u0026#34;] Para otimizar o build Docker em CI, use cache de dependências Gradle:\n// build.gradle.kts - Task para copiar dependências (util para cache Docker) tasks.register\u0026lt;Copy\u0026gt;(\u0026#34;copyDependencies\u0026#34;) { from(configurations.runtimeClasspath) into(\u0026#34;$buildDir/dependencies\u0026#34;) } Ferramentas de CI/CD GitHub Actions A ferramenta mais popular para projetos open source e muitas empresas:\nO workflow típico inclui:\nCheckout do código Setup do JDK 21 Cache de dependências Gradle Execução de testes Análise estática com detekt verificação de cobertura com kover Build da imagem Docker Deploy para staging/produção GitLab CI Popular em empresas que usam GitLab para hospedagem de código. Oferece pipelines visuais e integração nativa com Kubernetes.\nJenkins Ainda muito usado em empresas enterprise, especialmente bancos e fintechs. Oferece maxima flexibilidade mas exige mais manutenção.\nPipeline para Projeto Android Para projetos Android com Kotlin, o pipeline tem particularidades:\n// Pipeline Android típico: // 1. Build do APK/AAB // 2. Testes unitários // 3. Testes instrumentados (opcional, com emulador) // 4. Lint e detekt // 5. Publicação na Play Store (via Fastlane ou Gradle Play Publisher) // build.gradle.kts (app module) android { lint { abortOnError = true warningsAsErrors = true xmlReport = true } testOptions { unitTests.all { it.useJUnitPlatform() } } } // Plugin para publicação automática plugins { id(\u0026#34;com.github.triplet.play\u0026#34;) version \u0026#34;3.9.0\u0026#34; } play { serviceAccountCredentials.set(file(\u0026#34;play-service-account.json\u0026#34;)) track.set(\u0026#34;internal\u0026#34;) // internal -\u0026gt; alpha -\u0026gt; beta -\u0026gt; production defaultToAppBundles.set(true) } Melhores Práticas de CI/CD para Kotlin Cache de Dependências Gradle downloads podem levar minutos. Configurar cache e essencial:\n// Configuração de cache no build.gradle.kts buildCache { local { isEnabled = true directory = File(rootDir, \u0026#34;.gradle/build-cache\u0026#34;) } } Testes Paralelos // Executar testes em paralelo para reduzir tempo de CI tasks.withType\u0026lt;Test\u0026gt; { maxParallelForks = Runtime.getRuntime().availableProcessors() / 2 forkEvery = 100 // Reinicia JVM a cada 100 testes para evitar memory leaks } Build Incremental // Habilitar compilacao incremental kotlin { compilerOptions { freeCompilerArgs.add(\u0026#34;-Xuse-k2\u0026#34;) // Compilador K2 mais rapido } } Segredos e Configuração Nunca coloque segredos no código. Use variaveis de ambiente ou vault:\n// Acessar configurações de forma segura @Configuration class DatabaseConfig( @Value(\u0026#34;\\${DATABASE_URL}\u0026#34;) private val databaseUrl: String, @Value(\u0026#34;\\${DATABASE_USERNAME}\u0026#34;) private val username: String, @Value(\u0026#34;\\${DATABASE_PASSWORD}\u0026#34;) private val password: String ) { @Bean fun dataSource(): HikariDataSource { return HikariDataSource().apply { jdbcUrl = databaseUrl this.username = this@DatabaseConfig.username this.password = this@DatabaseConfig.password maximumPoolSize = 10 } } } Monitoramento do Pipeline Acompanhe métricas do seu pipeline:\nTempo médio de build: Deve ficar abaixo de 10 minutos para feedback rápido Taxa de falha: Acima de 10% indica problemas no processo Cobertura de testes: Mantenha acima de 80% para o core business Tempo de deploy: Do merge à produção, idealmente menos de 30 minutos Estratégias de Deploy Blue-Green Deployment Mantém duas versões do ambiente (blue e green). O deploy vai para o ambiente inativo, e após validação, o tráfego é direcionado para ele.\nCanary Release Direciona uma pequena porcentagem do tráfego (1-5%) para a nova versão. Se tudo estiver bem, aumenta gradualmente até 100%.\nRolling Update Atualiza instâncias gradualmente, substituindo uma por vez. É a abordagem padrão no Kubernetes.\nArgo CD com Kotlin: quando usar GitOps A consulta de Search Console que motivou esta atualização foi \u0026ldquo;argocd vs kotlin\u0026rdquo;. A comparação literal não faz sentido: Argo CD não compete com Kotlin. Argo CD é uma ferramenta de GitOps para publicar aplicações em Kubernetes; Kotlin é a linguagem usada para escrever a aplicação. Ainda assim, a busca revela uma dúvida real de quem trabalha com stacks modernas: como um serviço Kotlin entra em um fluxo GitOps?\nO desenho mais comum é:\no repositório da aplicação Kotlin roda testes, detekt, lint, cobertura e build; a pipeline gera uma imagem Docker versionada, por exemplo registry.exemplo.com/pedidos:1.42.0; a pipeline atualiza um repositório de manifests, Helm chart ou Kustomize com a nova tag; o Argo CD observa esse repositório de configuração e sincroniza o cluster; métricas, logs e health checks confirmam se o deploy ficou saudável. Nesse modelo, a pipeline de CI continua responsável por qualidade do código Kotlin. O Argo CD entra no CD operacional: ele garante que o estado do Kubernetes siga o que está declarado no Git. Isso reduz deploy manual, facilita rollback e cria uma trilha de auditoria clara para cada versão.\nUm exemplo simplificado de manifest para um serviço Kotlin/Spring Boot:\napiVersion: apps/v1 kind: Deployment metadata: name: pedidos-api spec: replicas: 3 selector: matchLabels: app: pedidos-api template: metadata: labels: app: pedidos-api spec: containers: - name: pedidos-api image: registry.exemplo.com/pedidos:1.42.0 ports: - containerPort: 8080 readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 A aplicação Kotlin precisa colaborar com esse fluxo. Em backend, exponha endpoints de health check com Spring Actuator ou Ktor; configure shutdown gracioso; não faça migração destrutiva de banco dentro do startup sem controle; e separe configuração por variável de ambiente ou Secret do Kubernetes.\nJenkins, GitHub Actions ou Argo CD? Uma dúvida comum em buscas de \u0026ldquo;Jenkins vs Kotlin\u0026rdquo; ou \u0026ldquo;ArgoCD vs Kotlin\u0026rdquo; é misturar linguagem com ferramenta de entrega. A tabela abaixo ajuda a organizar:\nFerramenta Papel no projeto Kotlin Quando escolher GitHub Actions CI/CD integrado ao GitHub Projetos pequenos e médios, open source, times que já usam GitHub GitLab CI CI/CD integrado ao GitLab Empresas com GitLab, runners internos e controle forte de pipeline Jenkins Orquestração flexível de pipelines Ambientes legados, integrações internas complexas, bancos e grandes empresas Argo CD GitOps e sincronização Kubernetes Deploy declarativo em cluster, múltiplos ambientes, rollback por Git Fastlane Publicação mobile Apps Android Kotlin com Play Store e esteiras mobile Para um backend Kotlin moderno, uma combinação muito saudável é GitHub Actions ou GitLab CI para build/teste e Argo CD para deploy Kubernetes. Para Android, Argo CD quase nunca é a peça principal; o foco costuma ser Gradle, emuladores, testes instrumentados, assinatura e Play Store.\nChecklist prático para CI/CD Kotlin em 2026 Use este checklist para revisar um projeto real:\n./gradlew test roda em toda alteração; dependências Gradle são cacheadas, mas sem esconder falhas de lockfile; detekt ou ktlint rodam antes do merge; cobertura é medida com Kover nos módulos críticos; builds Android geram APK/AAB de forma reproduzível; backends Kotlin geram imagem Docker com tag imutável; secrets ficam em vault, variável de ambiente ou Secret, nunca no repositório; health checks existem antes de usar rolling update, canary ou Argo CD; migrations têm estratégia de rollback ou compatibilidade entre versões; logs e métricas permitem saber se o deploy piorou latência, erro ou uso de memória. Se você ainda está começando, não tente implantar tudo no primeiro dia. O maior ganho inicial costuma vir de build, testes e análise estática confiáveis. Depois acrescente Docker, ambientes de staging, deploy automatizado e observabilidade.\nConclusão CI/CD bem implementado transforma a forma como você desenvolve e entrega software Kotlin. Automação de testes, análise estática, builds reprodutíveis e deploys automatizados criam um ciclo de feedback rápido que aumenta a qualidade e a velocidade de entrega.\nComece com o básico (build e testes automáticos) e evolua gradualmente para um pipeline completo com análise de código, cobertura de testes e deploy automatizado. Vale saber que muitas ferramentas de CI/CD como Docker, Kubernetes e Terraform são escritas em Go, e scripts de automação frequentemente usam Python. O investimento em CI/CD se paga rapidamente em menos bugs, menos trabalho manual e mais confiança em cada release.\n","permalink":"https://kotlin.dev.br/blog/kotlin-devops-ci-cd/","summary":"\u003cp\u003eDevOps e CI/CD não são mais diferenciais, são requisitos básicos em projetos profissionais. Para projetos Kotlin, montar pipelines de integração e entrega contínua garante qualidade, velocidade e confiança em cada deploy. Neste artigo, vamos explorar como configurar CI/CD eficaz para projetos Kotlin.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-cicd-e-por-que-importa\"\u003eO que é CI/CD e por que importa\u003c/h2\u003e\n\u003cp\u003eCI (Continuous Integration) é a prática de integrar código frequentemente, com verificações automáticas a cada push. CD (Continuous Delivery/Deployment) automatiza o processo de levar o código para produção.\u003c/p\u003e","title":"Kotlin e DevOps: CI/CD para Projetos Kotlin | Kotlin Brasil"},{"content":"O que é KSP em Kotlin? KSP (Kotlin Symbol Processing) é uma API desenvolvida pelo Google para processar anotações e gerar código em tempo de compilação em projetos Kotlin. Ele é o substituto moderno do kapt (Kotlin Annotation Processing Tool), oferecendo performance até 2x melhor ao trabalhar diretamente com os simbolos do Kotlin em vez de gerar stubs Java intermediarios.\nKSP entende conceitos nativos do Kotlin como propriedades, extension functions, nullable types e data classes, que o kapt (baseado no modelo Java) não consegue representar adequadamente.\nPor que KSP em vez de kapt? O kapt funciona gerando stubs Java a partir do código Kotlin, e depois executando processadores de anotacao Java padrão sobre esses stubs. Isso tem vários problemas:\nPerformance: gerar stubs e lento e consome memória. Perda de informação: conceitos Kotlin (como nullable, data class, sealed class) se perdem na traducao para Java. manutenção: os processadores precisam inferir informações Kotlin a partir da representacao Java. KSP resolve tudo isso acessando a arvore de simbolos Kotlin diretamente.\nConfigurando KSP no projeto // build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;1.9.22\u0026#34; id(\u0026#34;com.google.devtools.ksp\u0026#34;) version \u0026#34;1.9.22-1.0.17\u0026#34; } dependencies { // Adicionar processadores KSP ksp(\u0026#34;com.example:meu-processador:1.0.0\u0026#34;) } Para projetos multiplataforma:\nplugins { kotlin(\u0026#34;multiplatform\u0026#34;) version \u0026#34;1.9.22\u0026#34; id(\u0026#34;com.google.devtools.ksp\u0026#34;) version \u0026#34;1.9.22-1.0.17\u0026#34; } dependencies { add(\u0026#34;kspJvm\u0026#34;, \u0026#34;com.example:meu-processador:1.0.0\u0026#34;) add(\u0026#34;kspIosArm64\u0026#34;, \u0026#34;com.example:meu-processador:1.0.0\u0026#34;) } Criando um processador KSP simples Um processador KSP implementa a interface SymbolProcessor:\n// Processador import com.google.devtools.ksp.processing.* import com.google.devtools.ksp.symbol.* class MeuProcessador( private val codeGenerator: CodeGenerator, private val logger: KSPLogger ) : SymbolProcessor { override fun process(resolver: Resolver): List\u0026lt;KSAnnotated\u0026gt; { val simbolos = resolver.getSymbolsWithAnnotation(\u0026#34;com.example.AutoFactory\u0026#34;) .filterIsInstance\u0026lt;KSClassDeclaration\u0026gt;() simbolos.forEach { classe -\u0026gt; gerarFactory(classe) } // Retorna simbolos nao processados para uma proxima rodada return emptyList() } private fun gerarFactory(classe: KSClassDeclaration) { val nomeClasse = classe.simpleName.asString() val nomePacote = classe.packageName.asString() val nomeFactory = \u0026#34;${nomeClasse}Factory\u0026#34; val arquivo = codeGenerator.createNewFile( dependencies = Dependencies(true, classe.containingFile!!), packageName = nomePacote, fileName = nomeFactory ) arquivo.writer().use { writer -\u0026gt; writer.write(\u0026#34;\u0026#34;\u0026#34; package $nomePacote object $nomeFactory { fun criar(): $nomeClasse { return $nomeClasse() } } \u0026#34;\u0026#34;\u0026#34;.trimIndent()) } logger.info(\u0026#34;Factory gerada: $nomeFactory\u0026#34;) } } Provider do processador O processador precisa de um SymbolProcessorProvider:\nclass MeuProcessadorProvider : SymbolProcessorProvider { override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { return MeuProcessador( codeGenerator = environment.codeGenerator, logger = environment.logger ) } } Registre o provider no arquivo resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider:\ncom.example.MeuProcessadorProvider Exemplo prático: gerador de Builder // Anotacao annotation class AutoBuilder // Processador que gera builders class BuilderProcessador( private val codeGenerator: CodeGenerator, private val logger: KSPLogger ) : SymbolProcessor { override fun process(resolver: Resolver): List\u0026lt;KSAnnotated\u0026gt; { resolver.getSymbolsWithAnnotation(\u0026#34;com.example.AutoBuilder\u0026#34;) .filterIsInstance\u0026lt;KSClassDeclaration\u0026gt;() .forEach { gerarBuilder(it) } return emptyList() } private fun gerarBuilder(classe: KSClassDeclaration) { val nome = classe.simpleName.asString() val pacote = classe.packageName.asString() val propriedades = classe.primaryConstructor?.parameters ?: return val builder = buildString { appendLine(\u0026#34;package $pacote\u0026#34;) appendLine() appendLine(\u0026#34;class ${nome}Builder {\u0026#34;) propriedades.forEach { param -\u0026gt; val nomeProp = param.name?.asString() ?: return@forEach val tipo = param.type.resolve().declaration.qualifiedName?.asString() ?: \u0026#34;Any\u0026#34; appendLine(\u0026#34; var $nomeProp: $tipo? = null\u0026#34;) } appendLine() appendLine(\u0026#34; fun build(): $nome {\u0026#34;) val args = propriedades.joinToString(\u0026#34;, \u0026#34;) { param -\u0026gt; val n = param.name?.asString() ?: \u0026#34;\u0026#34; \u0026#34;$n = $n ?: throw IllegalStateException(\\\u0026#34;$n nao definido\\\u0026#34;)\u0026#34; } appendLine(\u0026#34; return $nome($args)\u0026#34;) appendLine(\u0026#34; }\u0026#34;) appendLine(\u0026#34;}\u0026#34;) } codeGenerator.createNewFile( Dependencies(true, classe.containingFile!!), pacote, \u0026#34;${nome}Builder\u0026#34; ).writer().use { it.write(builder) } } } Uso:\n@AutoBuilder data class Pessoa(val nome: String, val idade: Int) // Código gerado automaticamente: // PessoaBuilder com metodos nome(), idade() e build() fun main() { val pessoa = PessoaBuilder().apply { nome = \u0026#34;Ana\u0026#34; idade = 30 }.build() } Navegando a arvore de simbolos O KSP fornece uma API rica para inspecionar o código Kotlin:\nfun inspecionarClasse(classe: KSClassDeclaration) { // Nome e pacote val nome = classe.simpleName.asString() val pacote = classe.packageName.asString() // Modificadores val eDataClass = Modifier.DATA in classe.modifiers val eSealed = Modifier.SEALED in classe.modifiers // Propriedades classe.getAllProperties().forEach { prop -\u0026gt; val nomeProp = prop.simpleName.asString() val tipo = prop.type.resolve() val nullable = tipo.isMarkedNullable } // Funções classe.getAllFunctions().forEach { func -\u0026gt; val nomeFunc = func.simpleName.asString() val parametros = func.parameters } // Supertipos classe.superTypes.forEach { superTipo -\u0026gt; val tipoResolvido = superTipo.resolve() } } Quando usar KSP Reducao de boilerplate: gerar builders, factories, mappers e adaptadores automaticamente. Validação em tempo de compilação: verificar que anotações estao sendo usadas corretamente. Frameworks e bibliotecas: Room, Moshi, Koin e outras bibliotecas usam KSP para geracao de código. serialização customizada: gerar serializadores e desserializadores específicos. Documentação automatica: extrair informações do código para gerar documentação. Casos de Uso no Mundo Real Room Database no Android: A biblioteca Room usa KSP para gerar implementacoes de DAOs (Data Access Objects) e validar queries SQL em tempo de compilação. Ao anotar uma interface com @Dao, o KSP gera automaticamente todo o código de acesso ao banco de dados SQLite, eliminando boilerplate e garantindo que queries invalidas sejam detectadas antes da execução.\nMoshi e serialização JSON: O Moshi utiliza KSP para gerar adaptadores JSON eficientes a partir de data classes Kotlin. Em vez de usar reflexao em tempo de execução (lento e propenso a erros), o KSP analisa as propriedades da classe e gera código otimizado de serialização e desserializacao durante a compilação.\nKoin e injecao de dependências: O framework Koin utiliza KSP para verificar o grafo de dependências em tempo de compilação, detectando dependências circulares ou faltantes antes mesmo da aplicação ser executada.\nGeracao de código para APIs internas: Equipes que mantém SDKs internos usam KSP para gerar automaticamente classes de mapeamento entre modelos de API e modelos de dominio, garantindo que mudancas no schema da API sejam refletidas em erros de compilação em vez de falhas em producao.\nBoas Praticas Sempre mantenha a versão do KSP sincronizada com a versão do Kotlin. O formato de versionamento do KSP segue o padrão \u0026lt;versão-kotlin\u0026gt;-\u0026lt;versão-ksp\u0026gt; (ex: 1.9.22-1.0.17). Declare corretamente as dependências no CodeGenerator usando o parametro Dependencies, indicando quais arquivos fonte originaram o código gerado. Isso garante que o cache incremental funcione corretamente. Retorne simbolos não processados da função process() quando eles dependem de código gerado por outros processadores, permitindo que sejam processados em rodadas subsequentes. Use a API de teste kotlin-compile-testing para validar que seu processador gera código correto e que os erros de compilação esperados sao emitidos com mensagens claras. Prefira KSP a kapt em novos projetos. Se já usa kapt, migre gradualmente verificando se as bibliotecas que você utiliza já oferecem suporte a KSP. Perguntas Frequentes P: Posso usar KSP e kapt no mesmo projeto? R: Sim, ambos podem coexistir no mesmo modulo. Isso e útil durante a migração gradual de kapt para KSP. Porem, manter ambos significa que o projeto ainda incorre no custo de performance do kapt para os processadores que ainda não foram migrados.\nP: KSP funciona com Kotlin Multiplatform? R: Sim. O KSP suporta projetos Kotlin Multiplatform. Voce pode configurar processadores para targets específicos usando notacoes como kspJvm, kspIosArm64, etc. no bloco de dependências do Gradle.\nP: Qual a diferenca entre KSP e um plugin de compilador Kotlin? R: KSP opera no nivel de simbolos (classes, funções, propriedades) e só pode gerar novos arquivos, não modificar código existente. Um plugin de compilador tem acesso ao IR (Intermediate Representation) e pode transformar o código existente. KSP e mais simples de usar e mais estavel entre versões do Kotlin, enquanto plugins de compilador sao mais poderosos mas exigem manutenção constante.\nP: Como depurar um processador KSP? R: Voce pode usar logger.warn() ou logger.error() para emitir mensagens durante a compilação. Para depuração interativa, execute o build Gradle com a flag --no-daemon -Dorg.gradle.debug=true e conecte um debugger remoto na porta indicada.\nErros comuns Versão incompativel do KSP com Kotlin: a versão do KSP deve corresponder exatamente a versão do Kotlin (ex: KSP 1.9.22-1.0.17 para Kotlin 1.9.22).\nNao declarar dependencies corretamente: o CodeGenerator precisa saber de quais arquivos o código gerado depende para invalidacao correta do cache.\nProcessar na rodada errada: se um simbolo depende de código gerado por outro processador, ele pode não estar disponivel na primeira rodada. Retorne simbolos não processados da função process.\nIgnorar tipos nullable: diferente do kapt, KSP expõe nullability nativamente. Nao tratear isso gera código incorreto.\nNao testar o processador: KSP oferece uma API de teste (kotlin-compile-testing) para verificar que o código gerado esta correto.\nTermos relacionados Gradle Plugin: o plugin KSP e aplicado no build.gradle.kts para habilitar o processamento. Annotation: anotações que marcam classes e funções para processamento pelo KSP. Serialization: a biblioteca kotlinx.serialization usa um plugin de compilador similar para gerar código. kapt: o predecessor do KSP, baseado em annotation processing do Java. Code Generation: o resultado principal do KSP e gerar arquivos fonte que são compilados junto com o projeto. Kotlin Multiplatform: KSP suporta projetos multiplataforma, processando código de cada target. KSP e uma ferramenta poderosa para eliminar boilerplate e garantir segurança em tempo de compilação. Se você desenvolve bibliotecas ou frameworks em Kotlin, dominar KSP permite criar APIs que são ao mesmo tempo expressivas e eficientes.\n","permalink":"https://kotlin.dev.br/glossario/ksp/","summary":"\u003ch2 id=\"o-que-é-ksp-em-kotlin\"\u003eO que é KSP em Kotlin?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eKSP (Kotlin Symbol Processing)\u003c/strong\u003e é uma API desenvolvida pelo Google para processar anotações e gerar código em tempo de compilação em projetos Kotlin. Ele é o substituto moderno do \u003cstrong\u003ekapt\u003c/strong\u003e (Kotlin Annotation Processing Tool), oferecendo performance até 2x melhor ao trabalhar diretamente com os simbolos do Kotlin em vez de gerar stubs Java intermediarios.\u003c/p\u003e\n\u003cp\u003eKSP entende conceitos nativos do Kotlin como propriedades, extension functions, nullable types e data classes, que o kapt (baseado no modelo Java) não consegue representar adequadamente.\u003c/p\u003e","title":"KSP em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Job em Kotlin? O Job é o elemento do contexto de uma coroutine que representa seu ciclo de vida. Ele permite controlar a execução da coroutine: verificar se esta ativa, esperar sua conclusão ou cancela-la. Todo launch retorna um Job, e todo async retorna um Deferred (que é um subtipo de Job com resultado).\nPense no Job como a \u0026ldquo;alca\u0026rdquo; que você segura para controlar uma coroutine que esta rodando em background.\nSintaxe básica import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { delay(2000) println(\u0026#34;Coroutine finalizada\u0026#34;) } println(\u0026#34;Job ativo? ${job.isActive}\u0026#34;) // true println(\u0026#34;Job completo? ${job.isCompleted}\u0026#34;) // false job.join() // Espera a coroutine terminar println(\u0026#34;Job ativo? ${job.isActive}\u0026#34;) // false println(\u0026#34;Job completo? ${job.isCompleted}\u0026#34;) // true } O método join() suspende a coroutine atual até que o job termine. Diferente de Thread.join(), ele não bloqueia a thread.\nEstados do Job Um Job passa por vários estados durante sua vida:\nNew -\u0026gt; Active -\u0026gt; Completing -\u0026gt; Completed | v Cancelling -\u0026gt; Cancelled fun main() = runBlocking { val job = launch(start = CoroutineStart.LAZY) { println(\u0026#34;Executando...\u0026#34;) delay(1000) println(\u0026#34;Finalizado\u0026#34;) } println(\u0026#34;Novo: isActive=${job.isActive}\u0026#34;) // false job.start() println(\u0026#34;Ativo: isActive=${job.isActive}\u0026#34;) // true job.join() println(\u0026#34;Completo: isCompleted=${job.isCompleted}\u0026#34;) // true } Com CoroutineStart.LAZY, o job começa no estado \u0026ldquo;New\u0026rdquo; e só entra em \u0026ldquo;Active\u0026rdquo; quando você chama start() ou join().\nCancelamento de Jobs O cancelamento e cooperativo em Kotlin. Chamar cancel() não mata a coroutine instantaneamente \u0026ndash; ela precisa verificar o cancelamento:\nfun main() = runBlocking { val job = launch { repeat(1000) { i -\u0026gt; println(\u0026#34;Trabalhando... $i\u0026#34;) delay(100) // Ponto de suspensao: verifica cancelamento } } delay(500) println(\u0026#34;Cancelando...\u0026#34;) job.cancel() job.join() // Espera a coroutine finalizar o cancelamento // Ou: job.cancelAndJoin() // Combina cancel() + join() println(\u0026#34;Cancelado\u0026#34;) } Funções como delay, yield e withContext verificam o cancelamento automaticamente. Se sua coroutine faz trabalho intensivo de CPU sem pontos de suspensao, use isActive ou ensureActive():\nval job = launch(Dispatchers.Default) { var i = 0 while (isActive) { // Verifica cancelamento manualmente i++ // Trabalho intensivo de CPU } println(\u0026#34;Parou em $i\u0026#34;) } Hierarquia de Jobs (Structured Concurrency) Jobs formam uma hierarquia pai-filho. Quando uma coroutine lanca outra, o job filho e registrado no job pai:\nfun main() = runBlocking { val jobPai = launch { val jobFilho1 = launch { delay(2000) println(\u0026#34;Filho 1 finalizado\u0026#34;) } val jobFilho2 = launch { delay(1000) println(\u0026#34;Filho 2 finalizado\u0026#34;) } println(\u0026#34;Filhos lancados\u0026#34;) } delay(500) jobPai.cancel() // Cancela pai E todos os filhos jobPai.join() println(\u0026#34;Tudo cancelado\u0026#34;) } Regras da hierarquia:\nCancelar o pai cancela todos os filhos. Uma exceção não tratada em um filho cancela o pai e todos os irmaos. O pai só e considerado completo quando todos os filhos terminam. Job vs Deferred Deferred\u0026lt;T\u0026gt; e um Job que retorna um resultado:\nfun main() = runBlocking { val deferred: Deferred\u0026lt;Int\u0026gt; = async { delay(1000) 42 } // Deferred tem todas as funcionalidades de Job println(\u0026#34;Ativo: ${deferred.isActive}\u0026#34;) // Mais: pode obter o resultado val resultado = deferred.await() println(\u0026#34;Resultado: $resultado\u0026#34;) } Use launch (Job) quando não precisa de resultado; use async (Deferred) quando precisa.\nSupervisorJob O SupervisorJob modifica o comportamento de propagacao de erros: a falha de um filho não cancela os irmaos:\nfun main() = runBlocking { val supervisor = SupervisorJob() val scope = CoroutineScope(coroutineContext + supervisor) val job1 = scope.launch { delay(1000) throw RuntimeException(\u0026#34;Erro no job 1\u0026#34;) } val job2 = scope.launch { delay(2000) println(\u0026#34;Job 2 finalizado normalmente\u0026#34;) // Executa mesmo com erro no job1 } delay(3000) supervisor.cancel() } SupervisorJob e essencial em cenários onde tarefas são independentes e a falha de uma não deve afetar as outras.\nCompletable Job CompletableJob e um Job que pode ser completado manualmente:\nfun main() = runBlocking { val job = Job() // Cria um CompletableJob launch(job) { delay(1000) println(\u0026#34;Tarefa executada\u0026#34;) } job.complete() // Marca como completando (nao aceita mais filhos) job.join() // Espera filhos existentes terminarem println(\u0026#34;Tudo feito\u0026#34;) } Quando usar Job diretamente Cancelamento controlado: quando você precisa cancelar uma operação específica em resposta a uma acao do usuário. Esperar conclusão: quando uma parte do código depende de outra coroutine terminar antes de continuar. Monitorar estado: quando você precisa saber se uma coroutine ainda esta rodando. Escopo customizado: criar CoroutineScopes com Jobs específicos para controlar grupos de coroutines. Casos de Uso no Mundo Real Cancelamento de requisicoes de rede em Android: Quando o usuário navega para outra tela, o Job associado ao CoroutineScope da tela anterior e cancelado, abortando automaticamente todas as chamadas de API em andamento. Isso evita vazamentos de memória e atualizações de UI em telas que já não existem.\nProcessamento paralelo com controle de progresso: Em aplicações que processam lotes de dados (como upload de múltiplas imagens), cada tarefa e lancada como um Job filho. O Job pai permite monitorar o progresso geral, cancelar tudo se necessário, e garantir que o processo só e considerado completo quando todas as imagens foram enviadas.\nTarefas de background com timeout: Servicos que consultam APIs externas utilizam Jobs com withTimeout para garantir que uma requisicao lenta não bloqueie o sistema indefinidamente. O Job e cancelado automaticamente apos o tempo limite, liberando recursos.\nWorkers independentes com SupervisorJob: Em servidores backend com Ktor ou Spring, cada requisicao HTTP e tratada por um Job independente sob um SupervisorJob. Se uma requisicao falha com exceção, as demais continuam operando normalmente sem serem afetadas.\nBoas Praticas Use cancelAndJoin() em vez de chamar cancel() e join() separadamente para garantir que o cancelamento seja concluido antes de prosseguir. Sempre verifique isActive ou chame ensureActive() em loops de CPU intensivo para que o cancelamento cooperativo funcione corretamente. Prefira SupervisorJob quando as coroutines filhas sao independentes e a falha de uma não deve afetar as demais. Nunca capture CancellationException em blocos catch genericos. Se precisar capturar Exception, relance CancellationException explicitamente. Estruture suas coroutines com escopos adequados (como viewModelScope ou lifecycleScope no Android) em vez de usar GlobalScope, para que os Jobs sejam gerenciados automaticamente pelo ciclo de vida. Perguntas Frequentes P: Qual a diferenca entre Job e Deferred? R: Job representa uma coroutine que executa uma tarefa sem retornar resultado, criado com launch. Deferred e um subtipo de Job que carrega um valor de retorno, criado com async. Voce obtém o resultado de um Deferred chamando await(), enquanto com Job você apenas espera a conclusao com join().\nP: O que acontece quando um Job filho lanca uma exceção? R: Com um Job normal, a exceção propaga para o Job pai, que cancela todos os outros filhos e a si mesmo. Com SupervisorJob, a exceção fica isolada no filho que falhou, e os demais continuam executando normalmente.\nP: Por que o cancelamento de coroutines e cooperativo? R: O cancelamento cooperativo e uma decisao de design que evita problemas como corrupcao de dados e vazamento de recursos. Se uma coroutine fosse interrompida abruptamente, ela poderia deixar arquivos abertos ou transacoes incompletas. O modelo cooperativo permite que a coroutine finalize suas operações de limpeza antes de parar.\nP: Posso reutilizar um Job depois de cancelado? R: Nao. Um Job cancelado ou completado entra em um estado terminal e não pode ser reiniciado. Se você precisa executar a tarefa novamente, crie um novo Job com um novo launch ou async.\nErros comuns Nao chamar join apos cancel: cancel() apenas sinaliza o cancelamento. Sem join(), a coroutine pode continuar executando por um tempo. Use cancelAndJoin().\nIgnorar a cooperatividade do cancelamento: loops de CPU sem verificação de isActive ou pontos de suspensao não serao cancelados.\nUsar Job() como pai sem entender a propagacao: um Job criado manualmente com Job() segue as regras normais de propagacao de erro. Para isolamento, use SupervisorJob().\nEsquecer o tratamento de CancellationException: quando um job e cancelado, CancellationException e lancada. Ela deve ser propagada, não capturada em catch generico.\nNao estruturar coroutines: lancar coroutines com GlobalScope em vez de usar escopos estruturados perde todo o beneficio de hierarquia de Jobs.\nTermos relacionados Coroutine: a unidade de execução cujo ciclo de vida o Job representa. Deferred: subtipo de Job que carrega um resultado, retornado por async. SupervisorJob: job especial onde falha de filhos não propaga para irmaos. CoroutineScope: escopo que contém um Job e define o ciclo de vida das coroutines. Dispatcher: trabalha junto com o Job no contexto da coroutine, determinando onde ela executa. Structured Concurrency: o princípio de que coroutines formam hierarquias através de Jobs. O Job e a peça central do controle de ciclo de vida em Kotlin Coroutines. Dominar Jobs, cancelamento e hierarquia e fundamental para escrever código concorrente que seja robusto, previsivel e livre de vazamentos de recursos.\n","permalink":"https://kotlin.dev.br/glossario/job/","summary":"\u003ch2 id=\"o-que-é-job-em-kotlin\"\u003eO que é Job em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO \u003cstrong\u003eJob\u003c/strong\u003e é o elemento do contexto de uma coroutine que representa seu \u003cstrong\u003eciclo de vida\u003c/strong\u003e. Ele permite controlar a execução da coroutine: verificar se esta ativa, esperar sua conclusão ou cancela-la. Todo \u003ccode\u003elaunch\u003c/code\u003e retorna um Job, e todo \u003ccode\u003easync\u003c/code\u003e retorna um \u003ccode\u003eDeferred\u003c/code\u003e (que é um subtipo de Job com resultado).\u003c/p\u003e\n\u003cp\u003ePense no Job como a \u0026ldquo;alca\u0026rdquo; que você segura para controlar uma coroutine que esta rodando em background.\u003c/p\u003e","title":"Job em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Immutable em Kotlin? Imutabilidade (immutability) é o princípio de que um valor, uma vez criado, não pode ser alterado. Em Kotlin, a imutabilidade e fortemente encorajada e suportada pela linguagem em vários niveis: variaveis com val, coleções somente leitura, data classes com propriedades val e value classes.\nCódigo imutavel é mais fácil de entender, testar e paralelizar. Quando um objeto não muda, você não precisa se preocupar com quem mais pode estar modificando ele ao mesmo tempo.\nval vs var: o primeiro nível A forma mais básica de imutabilidade em Kotlin e usar val em vez de var:\nval nome = \u0026#34;Kotlin\u0026#34; // Imutavel: nao pode ser reatribuido var idade = 10 // Mutavel: pode ser reatribuido // nome = \u0026#34;Java\u0026#34; // Erro de compilacao! idade = 11 // OK Porem, val garante apenas que a referência não muda. O objeto apontado ainda pode ser mutavel:\nval lista = mutableListOf(1, 2, 3) lista.add(4) // OK! A referência nao mudou, mas o conteudo sim // lista = mutableListOf(5) // Erro! Nao pode reatribuir val Coleções somente leitura Kotlin distingue entre coleções somente leitura e mutaveis:\n// Somente leitura: nao expoe metodos de mutacao val nomes: List\u0026lt;String\u0026gt; = listOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;, \u0026#34;Carlos\u0026#34;) // nomes.add(\u0026#34;Diana\u0026#34;) // Erro de compilacao! // Mutavel: permite adicionar, remover, alterar val nomesMutaveis: MutableList\u0026lt;String\u0026gt; = mutableListOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;) nomesMutaveis.add(\u0026#34;Carlos\u0026#34;) // OK A mesma distincao existe para Set/MutableSet e Map/MutableMap:\nval mapaLeitura: Map\u0026lt;String, Int\u0026gt; = mapOf(\u0026#34;a\u0026#34; to 1, \u0026#34;b\u0026#34; to 2) val mapaMutavel: MutableMap\u0026lt;String, Int\u0026gt; = mutableMapOf(\u0026#34;a\u0026#34; to 1) mapaMutavel[\u0026#34;c\u0026#34;] = 3 // OK val conjuntoLeitura: Set\u0026lt;Int\u0026gt; = setOf(1, 2, 3) val conjuntoMutavel: MutableSet\u0026lt;Int\u0026gt; = mutableSetOf(1, 2) conjuntoMutavel.add(3) // OK Importante: as coleções \u0026ldquo;somente leitura\u0026rdquo; do Kotlin não são verdadeiramente imutáveis na JVM. Elas podem ser convertidas com cast para a versão mutavel. Para imutabilidade real, considere bibliotecas como kotlinx.collections.immutable.\nData classes imutáveis O padrão recomendado e criar data classes com todas as propriedades val:\ndata class Usuario( val id: Long, val nome: String, val email: String ) val usuario = Usuario(1, \u0026#34;Ana\u0026#34;, \u0026#34;ana@email.com\u0026#34;) // usuario.nome = \u0026#34;Maria\u0026#34; // Erro! Propriedade val // Para \u0026#34;modificar\u0026#34;, crie uma copia com copy() val usuarioAtualizado = usuario.copy(nome = \u0026#34;Maria\u0026#34;) println(usuario) // Usuario(id=1, nome=Ana, email=ana@email.com) println(usuarioAtualizado) // Usuario(id=1, nome=Maria, email=maria@email.com) O método copy() cria uma nova instancia com os campos alterados, sem modificar o original. Isso e a essencia da programação com dados imutáveis.\nImutabilidade profunda vs rasa Imutabilidade rasa (shallow) significa que a referência não muda, mas objetos internos podem:\ndata class Departamento(val nome: String, val membros: MutableList\u0026lt;String\u0026gt;) val dept = Departamento(\u0026#34;TI\u0026#34;, mutableListOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;)) dept.membros.add(\u0026#34;Carlos\u0026#34;) // Compila! A lista interna e mutavel Para imutabilidade profunda (deep), todos os campos internos também devem ser imutáveis:\ndata class DepartamentoImutavel(val nome: String, val membros: List\u0026lt;String\u0026gt;) val dept = DepartamentoImutavel(\u0026#34;TI\u0026#34;, listOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;)) // dept.membros.add(\u0026#34;Carlos\u0026#34;) // Erro! List nao tem add val deptAtualizado = dept.copy(membros = dept.membros + \u0026#34;Carlos\u0026#34;) Coleções persistentes com kotlinx.collections.immutable Para imutabilidade garantida e eficiente, use a biblioteca oficial:\nimport kotlinx.collections.immutable.* val lista = persistentListOf(1, 2, 3) val novaLista = lista.add(4) // Retorna nova lista, original inalterada println(lista) // [1, 2, 3] println(novaLista) // [1, 2, 3, 4] val mapa = persistentMapOf(\u0026#34;a\u0026#34; to 1, \u0026#34;b\u0026#34; to 2) val novoMapa = mapa.put(\u0026#34;c\u0026#34;, 3) Coleções persistentes usam estruturas de dados eficientes (como tries) que compartilham memória entre versões, evitando copiar tudo a cada modificacao.\nImutabilidade em concorrência A principal vantagem prática da imutabilidade e em código concorrente:\n// Seguro para acesso concorrente: dados nunca mudam data class Configuração( val maxConexoes: Int, val timeout: Long, val habilitarCache: Boolean ) val config = Configuração(10, 5000L, true) // Pode ser lido por qualquer thread sem sincronizacao launch(Dispatchers.Default) { usarConfig(config) } launch(Dispatchers.IO) { usarConfig(config) } Objetos imutáveis não precisam de locks, mutex ou qualquer mecanismo de sincronizacao. Eles são inerentemente thread-safe.\nSealed classes e imutabilidade Sealed classes combinam bem com imutabilidade para modelar estados:\nsealed class EstadoDaTela { object Carregando : EstadoDaTela() data class Sucesso(val dados: List\u0026lt;String\u0026gt;) : EstadoDaTela() data class Erro(val mensagem: String) : EstadoDaTela() } // Cada estado e imutavel; transicoes criam novos objetos var estado: EstadoDaTela = EstadoDaTela.Carregando estado = EstadoDaTela.Sucesso(listOf(\u0026#34;item1\u0026#34;, \u0026#34;item2\u0026#34;)) Quando usar imutabilidade Sempre que possível: a regra geral em Kotlin e preferir val sobre var e List sobre MutableList. Modelos de dados: data classes com propriedades val são o padrão ouro para representar dados. Estado de UI: em Compose e arquiteturas MVI/MVVM, o estado e imutavel e atualizado por substituicao. Concorrência: sempre que dados são compartilhados entre threads ou coroutines. APIs publicas: expor coleções somente leitura impede que consumidores modifiquem dados internos. Casos de Uso no Mundo Real Gerenciamento de estado em aplicações Compose/MVI: Em arquiteturas reativas como MVI, o estado da tela e representado por data classes imutaveis. Cada interação do usuário gera um novo estado via copy(), garantindo que a UI sempre reflita um snapshot consistente e que o histórico de estados possa ser rastreado para debugging.\nCache distribuido e serialização: Objetos imutaveis sao ideais para caching porque sua identidade nunca muda apos a criação. Em sistemas distribuidos com Redis ou Memcached, dados imutaveis podem ser serializados e compartilhados entre instancias sem risco de inconsistencia.\nEvent sourcing e auditoria: Sistemas financeiros e de compliance registram eventos como objetos imutaveis. Cada transacao bancaria, por exemplo, e representada como uma data class imutavel que nunca e alterada, criando um log de auditoria confiavel.\nConfiguracoes de aplicação: Objetos de configuração carregados no startup da aplicação sao naturalmente imutaveis. Uma vez lidos do arquivo ou variavel de ambiente, eles sao compartilhados entre todas as threads sem necessidade de sincronizacao.\nBoas Praticas Declare propriedades como val por padrão e só mude para var quando houver uma necessidade concreta de mutabilidade. Retorne List em vez de MutableList em APIs publicas. Use .toList() para criar uma copia somente leitura quando necessário. Em data classes, utilize apenas propriedades val e tipos imutaveis nos campos para garantir imutabilidade profunda. Considere a biblioteca kotlinx.collections.immutable quando precisar de garantias reais de imutabilidade e performance com colecoes persistentes. Use copy() para criar versões modificadas de objetos imutaveis em vez de tornar propriedades mutaveis. Perguntas Frequentes P: Qual a diferenca entre uma colecao somente leitura e uma colecao verdadeiramente imutavel? R: Uma colecao somente leitura (List, Map, Set) apenas esconde os métodos de mutação na interface, mas a implementação subjacente pode ser mutavel e acessivel via cast. Uma colecao verdadeiramente imutavel, como as da biblioteca kotlinx.collections.immutable, garante que o conteudo nunca pode ser alterado, mesmo com casts ou reflexao.\nP: Usar imutabilidade não causa problemas de performance por criar muitas copias? R: Na maioria dos casos, o impacto e insignificante. O garbage collector da JVM e otimizado para objetos de vida curta. Para colecoes grandes, estruturas persistentes (como as de kotlinx.collections.immutable) compartilham dados entre versões, evitando copias completas.\nP: Quando e aceitavel usar dados mutaveis em Kotlin? R: Mutabilidade e aceitavel em escopos locais e controlados, como variaveis dentro de uma função, builders durante a construcao de objetos, e em cenários de performance crítica onde a criação de copias seria um gargalo mensuravel.\nP: Como garantir imutabilidade profunda em uma data class com listas? R: Declare os campos de colecao com tipos somente leitura (List, Set, Map) e nunca passe instancias de MutableList diretamente. Use .toList() no construtor ou considere usar persistentListOf() da biblioteca de colecoes imutaveis.\nErros comuns Assumir que val significa imutavel: val impede reatribuicao da referência, mas o objeto pode ser mutavel internamente. Uma val lista: MutableList ainda permite modificacoes.\nExpor MutableList como retorno: retornar uma MutableList de uma função permite que o chamador modifique a colecao interna. Retorne List ou use .toList().\nUsar data class com propriedades var: isso quebra o contrato de imutabilidade e causa bugs sutis com hashCode/equals.\nCopiar tudo desnecessariamente: em coleções grandes, criar copias completas a cada modificacao e ineficiente. Use coleções persistentes.\nEsquecer imutabilidade profunda: ter um data class com val mas com campos que são MutableList internamente.\nTermos relacionados val: palavra-chave que declara uma referência somente leitura (não reatribuivel). var: palavra-chave que declara uma referência mutavel. Data Class: classe que gera automaticamente copy(), facilitando a criação de versões modificadas de objetos imutáveis. Value Class: tipo inline que encapsula um valor de forma imutavel sem overhead. Sealed Class: hierarquia fechada que modela estados imutáveis de forma segura. Collections: a biblioteca padrão distingue entre coleções somente leitura e mutaveis. Imutabilidade e um dos pilares do Kotlin idiomatico. A linguagem facilita a escrita de código imutavel em todos os niveis, desde variaveis simples até estruturas de dados complexas. Adotar imutabilidade como padrão torna o código mais previsivel, testavel e seguro em ambientes concorrentes.\n","permalink":"https://kotlin.dev.br/glossario/immutable/","summary":"\u003ch2 id=\"o-que-é-immutable-em-kotlin\"\u003eO que é Immutable em Kotlin?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eImutabilidade\u003c/strong\u003e (immutability) é o princípio de que um valor, uma vez criado, \u003cstrong\u003enão pode ser alterado\u003c/strong\u003e. Em Kotlin, a imutabilidade e fortemente encorajada e suportada pela linguagem em vários niveis: variaveis com \u003ccode\u003eval\u003c/code\u003e, coleções somente leitura, data classes com propriedades \u003ccode\u003eval\u003c/code\u003e e value classes.\u003c/p\u003e\n\u003cp\u003eCódigo imutavel é mais fácil de entender, testar e paralelizar. Quando um objeto não muda, você não precisa se preocupar com quem mais pode estar modificando ele ao mesmo tempo.\u003c/p\u003e","title":"Immutable em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é tailrec em Kotlin? A palavra-chave tailrec em Kotlin instrui o compilador a otimizar uma função recursiva transformando-a em um loop iterativo nos bastidores. Isso elimina o risco de estouro de pilha (StackOverflowError) que funções recursivas tradicionais apresentam quando processam grandes volumes de dados.\nRecursão de cauda (tail recursion) acontece quando a chamada recursiva é a ultima operação executada pela função. Nesse cenário, o compilador não precisa manter o stack frame anterior, pois não há mais nenhum calculo pendente apos o retorno da chamada recursiva. O modificador tailrec garante que o compilador Kotlin realize essa otimização e, caso a função não seja elegivel, emite um aviso em tempo de compilação.\nSintaxe básica A sintaxe para declarar uma função com tailrec e direta. Basta adicionar o modificador antes da palavra fun:\ntailrec fun fatorial(n: Long, acumulador: Long = 1): Long { if (n \u0026lt;= 1) return acumulador return fatorial(n - 1, n * acumulador) } fun main() { println(fatorial(20)) // 2432902008176640000 println(fatorial(50)) // funciona sem estouro de pilha } Observe que o parametro acumulador carrega o resultado parcial. Essa técnica e fundamental para transformar uma recursão comum em recursão de cauda.\nComparação com recursão tradicional Uma implementação recursiva clássica do fatorial seria:\nfun fatorialClassico(n: Long): Long { if (n \u0026lt;= 1) return 1 return n * fatorialClassico(n - 1) // multiplicacao APOS a chamada recursiva } Nessa versão, a multiplicacao n * fatorialClassico(n - 1) acontece depois do retorno da chamada recursiva. Isso impede a otimização de cauda porque o compilador precisa manter cada frame na pilha para realizar a multiplicacao pendente. Com números grandes, isso causa StackOverflowError.\nExemplos práticos Soma de uma lista tailrec fun somaLista(lista: List\u0026lt;Int\u0026gt;, indice: Int = 0, acumulador: Long = 0): Long { if (indice \u0026gt;= lista.size) return acumulador return somaLista(lista, indice + 1, acumulador + lista[indice]) } fun main() { val numeros = (1..1_000_000).toList() println(somaLista(numeros)) // 500000500000 } Busca binaria recursiva tailrec fun buscaBinaria( lista: List\u0026lt;Int\u0026gt;, alvo: Int, inicio: Int = 0, fim: Int = lista.size - 1 ): Int { if (inicio \u0026gt; fim) return -1 val meio = (inicio + fim) / 2 return when { lista[meio] == alvo -\u0026gt; meio lista[meio] \u0026lt; alvo -\u0026gt; buscaBinaria(lista, alvo, meio + 1, fim) else -\u0026gt; buscaBinaria(lista, alvo, inicio, meio - 1) } } fun main() { val ordenada = (1..1_000_000).toList() println(buscaBinaria(ordenada, 750_000)) // 749999 } Fibonacci com tailrec tailrec fun fibonacci(n: Int, a: Long = 0, b: Long = 1): Long { if (n == 0) return a return fibonacci(n - 1, b, a + b) } fun main() { println(fibonacci(10)) // 55 println(fibonacci(50)) // 12586269025 println(fibonacci(90)) // 2880067194370816120 } Maximo divisor comum (MDC) tailrec fun mdc(a: Int, b: Int): Int { if (b == 0) return a return mdc(b, a % b) } fun main() { println(mdc(48, 18)) // 6 println(mdc(1071, 462)) // 21 } Como o compilador transforma o código Quando você marca uma função com tailrec, o compilador Kotlin gera bytecode equivalente a um loop while. O fatorial com tailrec, por exemplo, e compilado para algo semelhante a:\nfun fatorialOtimizado(n: Long, acumulador: Long = 1): Long { var nAtual = n var acAtual = acumulador while (true) { if (nAtual \u0026lt;= 1) return acAtual acAtual = nAtual * acAtual nAtual = nAtual - 1 } } Essa transformacao elimina completamente a recursão no bytecode final, garantindo performance constante em termos de uso de pilha independentemente da profundidade da recursão.\nQuando usar tailrec O tailrec e indicado nas seguintes situacoes:\nAlgoritmos naturalmente recursivos como travessia de arvores, busca binaria, calculo de sequencias matematicas e processamento de listas encadeadas. Processamento de grandes volumes de dados onde a profundidade da recursão pode ultrapassar o limite da pilha da JVM. Substituicao de loops complexos onde a lógica recursiva e mais legivel que a iterativa equivalente. Programação funcional quando você adota um estilo funcional e quer evitar mutação de estado sem sacrificar performance. Quando não usar Nem toda função recursiva pode ser convertida para tail recursion. Nao use tailrec quando:\nA chamada recursiva não e a ultima operação da função. Ha mais de uma chamada recursiva no corpo da função (como na versão clássica de Fibonacci sem acumulador). A função usa blocos try/catch envolvendo a chamada recursiva. A simplicidade do loop iterativo torna a recursão desnecessaria. Casos de Uso no Mundo Real Parsers e interpretadores de linguagens: compiladores e interpretadores frequentemente usam tailrec para percorrer arvores sintaticas e avaliar expressoes recursivamente. Como a profundidade da arvore pode ser grande em arquivos de código extensos, a otimização de cauda evita estouros de pilha durante a analise.\nProcessamento de estruturas de dados encadeadas: aplicações que manipulam listas encadeadas, arvores ou grafos usam tailrec para percorrer nodos sequencialmente. Isso e comum em bibliotecas de estruturas de dados funcionais e em algoritmos de busca em profundidade iterativa.\nAlgoritmos matematicos e criptograficos: calculos como MDC (maximo divisor comum), exponenciacao modular e geracoes de sequencias matematicas (Fibonacci, Collatz) se beneficiam de tailrec por serem naturalmente recursivos e potencialmente profundos para valores grandes.\nMaquinas de estado e protocolos de comunicação: implementacoes de maquinas de estado que transitam entre estados através de chamadas recursivas usam tailrec para garantir que longas sequencias de transicoes não esgotem a pilha. Isso e relevante em protocolos de rede e processamento de eventos.\nBoas Praticas Sempre use um parametro acumulador para carregar o resultado parcial entre chamadas recursivas. Essa e a tecnica fundamental para transformar recursao comum em recursao de cauda. Preste atencao nos avisos do compilador. Se o Kotlin emitir \u0026ldquo;A function is marked as tail-recursive but no tail calls are found\u0026rdquo;, revise a função para garantir que a chamada recursiva e realmente a ultima operação. Prefira tailrec a loops quando a lógica recursiva for mais clara e expressiva que a iterativa equivalente. Nao force o uso de tailrec se um simples for ou while resolve o problema com mais clareza. Evite envolver a chamada recursiva em blocos try-catch, pois isso impede a otimização de cauda. Trate erros antes da chamada recursiva ou use um wrapper externo. Escreva testes com valores grandes (por exemplo, n = 100_000) para confirmar que a otimização esta funcionando. Se a função lanca StackOverflowError com valores altos, a recursao de cauda não esta sendo aplicada corretamente. Perguntas Frequentes P: O que acontece se eu marcar uma função com tailrec mas ela não for elegivel para otimização? R: O compilador Kotlin emite um aviso em tempo de compilação informando que nenhuma chamada de cauda foi encontrada. A função compila e executa normalmente, mas sem a otimização \u0026ndash; ou seja, ela ainda pode causar StackOverflowError com recursoes profundas.\nP: O tailrec funciona com funções que tem mais de um branch recursivo? R: Cada branch individual pode ser uma chamada de cauda válida. O problema ocorre quando um branch realiza uma operação apos a chamada recursiva. Se todos os branches recursivos tem a chamada como ultima operação, a otimização funciona. Se apenas alguns branches sao de cauda, o compilador emite aviso e não otimiza.\nP: Existe diferenca de performance entre tailrec e um loop while escrito manualmente? R: Nao. O compilador transforma a função tailrec em um loop no bytecode, gerando código equivalente a um while. A performance em tempo de execução e identica. A escolha entre tailrec e loop manual e uma questao de legibilidade e estilo de programacao.\nP: Posso usar tailrec em funções suspensas (suspend functions)? R: Nao. O modificador tailrec não e compativel com funções suspend em Kotlin. funções suspensas tem um mecanismo de continuacao que impede a otimização de cauda pelo compilador. Para recursao em funções suspensas, considere usar loops iterativos ou sequence.\nErros comuns Recursão que não e de cauda // ERRADO: o compilador emite aviso tailrec fun somaAte(n: Int): Int { if (n \u0026lt;= 0) return 0 return n + somaAte(n - 1) // operacao APOS a chamada recursiva } O compilador Kotlin emite o aviso: \u0026ldquo;A function is marked as tail-recursive but no tail calls are found.\u0026rdquo; A função compila, mas sem a otimização desejada.\nCorreção com acumulador // CORRETO: recursão de cauda com acumulador tailrec fun somaAte(n: Int, acumulador: Int = 0): Int { if (n \u0026lt;= 0) return acumulador return somaAte(n - 1, acumulador + n) } Chamar a função dentro de expressoes // ERRADO: chamada dentro de when com operacoes tailrec fun processar(n: Int): String { return when { n \u0026lt;= 0 -\u0026gt; \u0026#34;fim\u0026#34; n % 2 == 0 -\u0026gt; \u0026#34;par: \u0026#34; + processar(n - 1) // concatenacao apos chamada else -\u0026gt; processar(n - 1) } } Nesse caso, apenas o branch else e uma chamada de cauda válida. O branch com concatenacao impede a otimização completa.\nUso com funções de extensao O tailrec também funciona com funções de extensao, desde que a chamada recursiva siga as regras de cauda:\ntailrec fun List\u0026lt;Int\u0026gt;.somarElementos(indice: Int = 0, acumulador: Long = 0): Long { if (indice \u0026gt;= this.size) return acumulador return this.somarElementos(indice + 1, acumulador + this[indice]) } Termos relacionados Recursão: técnica onde uma função chama a si mesma para resolver subproblemas menores. Stack overflow: erro que ocorre quando a pilha de execução excede seu limite por excesso de chamadas empilhadas. Função de ordem superior: funções que recebem ou retornam outras funções, frequentemente combinadas com recursão. Programação funcional: paradigma que favorece imutabilidade e recursão sobre loops e estado mutavel. inline: modificador que instrui o compilador a copiar o corpo da função no ponto de chamada, outra forma de otimização em Kotlin. Sequence: tipo lazy de Kotlin que pode substituir recursão para processamento de coleções grandes. Conclusão O modificador tailrec e uma ferramenta valiosa para quem escreve Kotlin em estilo funcional. Ele permite expressar algoritmos recursivos de forma clara e segura, sem risco de estouro de pilha. A chave para usa-lo corretamente e garantir que a chamada recursiva seja sempre a ultima operação da função, utilizando parametros acumuladores quando necessário. Com essa técnica, você combina a elegancia da recursão com a eficiencia de um loop iterativo.\n","permalink":"https://kotlin.dev.br/glossario/tailrec/","summary":"\u003ch2 id=\"o-que-é-tailrec-em-kotlin\"\u003eO que é \u003ccode\u003etailrec\u003c/code\u003e em Kotlin?\u003c/h2\u003e\n\u003cp\u003eA palavra-chave \u003ccode\u003etailrec\u003c/code\u003e em Kotlin instrui o compilador a otimizar uma função recursiva transformando-a em um loop iterativo nos bastidores. Isso elimina o risco de estouro de pilha (StackOverflowError) que funções recursivas tradicionais apresentam quando processam grandes volumes de dados.\u003c/p\u003e\n\u003cp\u003eRecursão de cauda (tail recursion) acontece quando a chamada recursiva é a ultima operação executada pela função. Nesse cenário, o compilador não precisa manter o stack frame anterior, pois não há mais nenhum calculo pendente apos o retorno da chamada recursiva. O modificador \u003ccode\u003etailrec\u003c/code\u003e garante que o compilador Kotlin realize essa otimização e, caso a função não seja elegivel, emite um aviso em tempo de compilação.\u003c/p\u003e","title":"Tailrec em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Gradle Plugin em Kotlin? Um Gradle Plugin é um modulo que estende as capacidades do sistema de build Gradle, adicionando tarefas, configurações e convenções ao projeto. No ecossistema Kotlin, o plugin mais importante é o Kotlin Gradle Plugin (org.jetbrains.kotlin.jvm, org.jetbrains.kotlin.multiplatform, etc.), que ensina o Gradle a compilar código Kotlin.\nAlem do plugin oficial do Kotlin, existem dezenas de plugins que automatizam tarefas comuns: serialização, geracaco de código, análise estática, publicacao de bibliotecas é muito mais.\nAplicando o Kotlin Gradle Plugin A forma moderna de aplicar plugins usa o bloco plugins no build.gradle.kts:\nplugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;1.9.22\u0026#34; } repositories { mavenCentral() } dependencies { implementation(kotlin(\u0026#34;stdlib\u0026#34;)) testImplementation(kotlin(\u0026#34;test\u0026#34;)) } Para projetos Android:\nplugins { id(\u0026#34;com.android.application\u0026#34;) kotlin(\u0026#34;android\u0026#34;) version \u0026#34;1.9.22\u0026#34; } Para projetos multiplataforma:\nplugins { kotlin(\u0026#34;multiplatform\u0026#34;) version \u0026#34;1.9.22\u0026#34; } kotlin { jvm() iosArm64() iosSimulatorArm64() sourceSets { commonMain.dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3\u0026#34;) } } } Plugins comuns no ecossistema Kotlin O ecossistema Kotlin tem vários plugins essenciais:\nplugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;1.9.22\u0026#34; kotlin(\u0026#34;plugin.serialization\u0026#34;) version \u0026#34;1.9.22\u0026#34; // kotlinx.serialization id(\u0026#34;com.google.devtools.ksp\u0026#34;) version \u0026#34;1.9.22-1.0.17\u0026#34; // KSP id(\u0026#34;org.jetbrains.compose\u0026#34;) version \u0026#34;1.5.12\u0026#34; // Compose Multiplatform } Cada plugin adiciona funcionalidades específicas:\nkotlin-serialization: gera código de serialização em tempo de compilação. KSP (Kotlin Symbol Processing): processa anotações e gera código. Compose: habilita o compilador do Jetpack Compose. Criando um Gradle Plugin customizado Você pode criar seus próprios plugins para automatizar tarefas específicas do projeto. A forma mais simples e um plugin no buildSrc:\n// buildSrc/src/main/kotlin/MeuPlugin.kt import org.gradle.api.Plugin import org.gradle.api.Project class MeuPlugin : Plugin\u0026lt;Project\u0026gt; { override fun apply(projeto: Project) { projeto.tasks.register(\u0026#34;saudacao\u0026#34;) { group = \u0026#34;custom\u0026#34; description = \u0026#34;Exibe uma saudacao\u0026#34; doLast { println(\u0026#34;Ola do MeuPlugin!\u0026#34;) } } } } // buildSrc/build.gradle.kts plugins { `kotlin-dsl` } repositories { mavenCentral() } // build.gradle.kts (no projeto principal) plugins { id(\u0026#34;meu-plugin\u0026#34;) // Registrado automaticamente pelo buildSrc } Plugin com extension (configuração customizada) Plugins mais sofisticados usam extensions para permitir configuração:\n// Definir a extension open class MinhaConfiguracao { var nomeDoApp: String = \u0026#34;MeuApp\u0026#34; var versao: String = \u0026#34;1.0.0\u0026#34; var habilitarLogs: Boolean = false } class PluginConfiguravelPlugin : Plugin\u0026lt;Project\u0026gt; { override fun apply(projeto: Project) { val config = projeto.extensions.create(\u0026#34;minhaConfig\u0026#34;, MinhaConfiguracao::class.java) projeto.afterEvaluate { projeto.tasks.register(\u0026#34;info\u0026#34;) { doLast { println(\u0026#34;App: ${config.nomeDoApp}\u0026#34;) println(\u0026#34;Versão: ${config.versao}\u0026#34;) println(\u0026#34;Logs: ${config.habilitarLogs}\u0026#34;) } } } } } Uso no build.gradle.kts:\nminhaConfig { nomeDoApp = \u0026#34;KotlinBrasil\u0026#34; versao = \u0026#34;2.0.0\u0026#34; habilitarLogs = true } Convention Plugins Uma prática moderna e criar convention plugins que padronizam configurações em projetos multi-modulo:\n// build-logic/convention/src/main/kotlin/kotlin-library-convention.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) } kotlin { jvmToolchain(17) } tasks.withType\u0026lt;Test\u0026gt; { useJUnitPlatform() } dependencies { testImplementation(kotlin(\u0026#34;test\u0026#34;)) } // Qualquer modulo do projeto plugins { id(\u0026#34;kotlin-library-convention\u0026#34;) } // Automaticamente herda todas as configurações do convention plugin Isso evita duplicacao de configuração entre modulos e garante consistencia.\nVersion Catalogs com plugins O Gradle Version Catalog centraliza versões de dependências e plugins:\n# gradle/libs.versions.toml [versions] kotlin = \u0026#34;1.9.22\u0026#34; ksp = \u0026#34;1.9.22-1.0.17\u0026#34; [plugins] kotlin-jvm = { id = \u0026#34;org.jetbrains.kotlin.jvm\u0026#34;, version.ref = \u0026#34;kotlin\u0026#34; } kotlin-serialization = { id = \u0026#34;org.jetbrains.kotlin.plugin.serialization\u0026#34;, version.ref = \u0026#34;kotlin\u0026#34; } ksp = { id = \u0026#34;com.google.devtools.ksp\u0026#34;, version.ref = \u0026#34;ksp\u0026#34; } // build.gradle.kts plugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.serialization) } Quando usar Gradle Plugins Compilação de Kotlin: o plugin kotlin-jvm ou kotlin-multiplatform e obrigatório para compilar Kotlin. Geracao de código: plugins como KSP e serialization geram código em tempo de compilação, evitando boilerplate. Padronizacao: convention plugins garantem que todos os modulos de um projeto seguem as mesmas regras. Automação: tarefas repetitivas como publicacao, geracao de documentação e análise de código podem ser automatizadas com plugins. Integração: plugins conectam o build a ferramentas externas como Docker, Kubernetes, AWS. Casos de Uso no Mundo Real configuração padronizada em projetos multi-modulo: empresas com dezenas de modulos Kotlin usam convention plugins para garantir que todos os modulos compartilhem a mesma versão do JDK, as mesmas regras de compilação e as mesmas dependências de teste. Isso elimina duplicacao de configuração e reduz erros causados por inconsistencias entre modulos.\nGeracao automatica de código com KSP: projetos que usam bibliotecas como Room, Moshi ou Hilt aplicam o plugin KSP para processar anotacoes e gerar código em tempo de compilação. O plugin elimina boilerplate manual e garante que o código gerado esteja sempre sincronizado com as definicoes das anotacoes.\nPipeline de CI/CD com publicacao automatizada: plugins customizados automatizam o processo de versionamento, geracao de changelogs e publicacao de artefatos no Maven Central ou em repositórios privados. Um único comando ./gradlew publish executa todo o pipeline configurado pelo plugin.\nAnalise estática e qualidade de código: plugins como Detekt e Ktlint sao aplicados para impor regras de estilo e detectar problemas de código em tempo de build. Eles podem ser configurados para falhar o build quando violacoes criticas sao encontradas, garantindo a qualidade do código antes do merge.\nBoas Praticas Utilize Version Catalogs (libs.versions.toml) para centralizar todas as versões de plugins e dependências em um único arquivo. Isso facilita atualizações e garante consistencia entre modulos do projeto. Crie convention plugins no diretorio build-logic para configuracoes reutilizaveis em vez de duplicar blocos de configuração em cada build.gradle.kts. Isso segue o princípio DRY e facilita a manutenção. Verifique a matriz de compatibilidade entre versões do Kotlin Gradle Plugin, KSP e outros plugins antes de atualizar. Incompatibilidades entre versões sao uma das causas mais frequentes de falhas de build. Habilite o build cache e a compilação incremental do Kotlin para acelerar builds. Configure kotlin.incremental=true e org.gradle.caching=true no gradle.properties. Prefira a DSL plugins {} com type-safe accessors em vez da sintaxe legada apply plugin. A DSL moderna oferece autocompletar no IDE, verificação de tipos e melhor legibilidade. Perguntas Frequentes P: Qual a diferenca entre um plugin aplicado com kotlin(\u0026quot;jvm\u0026quot;) e id(\u0026quot;org.jetbrains.kotlin.jvm\u0026quot;)? R: Sao equivalentes. A função kotlin(\u0026quot;jvm\u0026quot;) e um atalho (sugar syntax) fornecido pelo Gradle que se expande para id(\u0026quot;org.jetbrains.kotlin.jvm\u0026quot;). Ambas as formas aplicam exatamente o mesmo plugin. A forma curta e mais legivel e preferida pela comunidade.\nP: Quando devo criar um plugin customizado em vez de usar scripts de build? R: Crie um plugin customizado quando a lógica de build precisa ser reutilizada em múltiplos projetos ou modulos, quando a configuração e complexa o suficiente para se beneficiar de testes unitarios, ou quando você quer distribuir a lógica como um artefato independente. Para lógica simples e específica de um projeto, scripts no buildSrc ou build-logic sao suficientes.\nP: O que e buildSrc e como ele se compara a build-logic? R: O buildSrc e um diretorio especial reconhecido automaticamente pelo Gradle, cujo código e compilado antes de qualquer script de build. O build-logic (ou build-conventions) e um included build configurado manualmente que oferece mais flexibilidade, como a possibilidade de cachear a compilação e evitar invalidacao de todo o build quando o código muda. Projetos modernos preferem build-logic com included builds.\nP: Como posso depurar problemas causados por plugins do Gradle? R: Use ./gradlew build --info ou --debug para logs detalhados. O comando ./gradlew buildEnvironment mostra todos os plugins aplicados e suas versões. Para conflitos de dependência, ./gradlew dependencies exibe a arvore completa. Tambem e possível executar o build com --scan para gerar um relatorio interativo no Gradle Build Scan.\nErros comuns Versão incompativel entre plugins: o Kotlin Gradle Plugin, KSP e outros plugins precisam ter versões compatíveis. Verifique a matriz de compatibilidade antes de atualizar.\nAplicar plugins na ordem errada: em projetos Android, o plugin Android deve ser aplicado antes do Kotlin. A ordem dos plugins pode afetar o comportamento do build.\nUsar apply em vez de plugins: a sintaxe antiga apply plugin: 'kotlin' ainda funciona, mas a DSL plugins { } e type-safe e preferida.\nConfigurar o plugin fora do bloco correto: cada plugin tem seu bloco de configuração específico. Configurar no lugar errado causa erros silenciosos ou inesperados.\nNao cachear builds: o Kotlin Gradle Plugin suporta incremental compilation e build cache. Nao configurar isso pode deixar o build muito mais lento do que necessário.\nTarefas úteis do Kotlin Gradle Plugin # Compilar o projeto ./gradlew compileKotlin # Executar testes ./gradlew test # Verificar dependências ./gradlew dependencies # Limpar e reconstruir ./gradlew clean build Termos relacionados KSP (Kotlin Symbol Processing): plugin para processamento de anotações e geracao de código em Kotlin. Kotlin Multiplatform: plugin que habilita compilação para múltiplas plataformas. Serialization: plugin que gera serializadores em tempo de compilação. buildSrc: diretorio especial do Gradle para lógica de build compartilhada. Version Catalog: sistema de gerenciamento centralizado de versões de dependências e plugins. Convention Plugin: plugin que padroniza configurações entre modulos de um projeto. Gradle Plugins são a espinha dorsal do sistema de build no ecossistema Kotlin. Entender como aplica-los, configura-los e, quando necessário, cria-los, e uma habilidade essencial para qualquer desenvolvedor Kotlin que trabalhe em projetos profissionais.\n","permalink":"https://kotlin.dev.br/glossario/gradle-plugin/","summary":"\u003ch2 id=\"o-que-é-gradle-plugin-em-kotlin\"\u003eO que é Gradle Plugin em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUm \u003cstrong\u003eGradle Plugin\u003c/strong\u003e é um modulo que estende as capacidades do sistema de build \u003cstrong\u003eGradle\u003c/strong\u003e, adicionando tarefas, configurações e convenções ao projeto. No ecossistema Kotlin, o plugin mais importante é o \u003cstrong\u003eKotlin Gradle Plugin\u003c/strong\u003e (\u003ccode\u003eorg.jetbrains.kotlin.jvm\u003c/code\u003e, \u003ccode\u003eorg.jetbrains.kotlin.multiplatform\u003c/code\u003e, etc.), que ensina o Gradle a compilar código Kotlin.\u003c/p\u003e\n\u003cp\u003eAlem do plugin oficial do Kotlin, existem dezenas de plugins que automatizam tarefas comuns: serialização, geracaco de código, análise estática, publicacao de bibliotecas é muito mais.\u003c/p\u003e","title":"Gradle Plugin em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"A comunidade Kotlin no Brasil esta vibrante e em pleno crescimento. De grupos no Telegram a conferencias presenciais, há inumeras formas de se conectar com outros desenvolvedores, aprender e contribuir. Neste artigo, vamos mapear toda a comunidade Kotlin brasileira e te mostrar como fazer parte dela.\nO Estado da Comunidade Kotlin no Brasil O Brasil é um dos maiores mercados de desenvolvimento mobile do mundo, e com Kotlin sendo a linguagem oficial do Android, a comunidade cresceu organicamente. Mas o ecossistema vai muito além do mobile: desenvolvedores backend, multiplatform e até web contribuem para uma comunidade diversa e acolhedora.\nAlguns números que ilustram o tamanho da comunidade:\nMilhares de desenvolvedores Kotlin ativos no Brasil Dezenas de grupos online com participacao diaria Eventos regulares em diversas cidades Crescente producao de conteudo em português Grupos e Canais Online Telegram O Telegram é a principal plataforma de comunicação da comunidade Kotlin brasileira:\nKotlin Brasil: O maior grupo nacional, com discussoes diarias sobre a linguagem, duvidas tecnicas e compartilhamento de vagas Android Dev BR: Embora focado em Android, Kotlin é a linguagem predominante nas discussoes Kotlin Multiplatform BR: Grupo específico para quem trabalha ou quer aprender KMP Discord Servidores Discord também tem crescido como espaco de comunidade:\nDev Brasil: Servidor amplo com canal dedicado a Kotlin JVM Brasil: Focado em tecnologias JVM, com forte presenca de Kotlin Stack Overflow em Português O Stack Overflow em português tem uma comunidade ativa de Kotlin. Responder perguntas la é uma excelente forma de:\nSolidificar seu conhecimento Ganhar visibilidade na comunidade Ajudar iniciantes Eventos e Conferencias KotlinConf A KotlinConf é o principal evento global de Kotlin, organizado pela JetBrains. Embora aconteca na Europa, a transmissao online permite participacao de brasileiros. Muitos desenvolvedores brasileiros já palestram no evento, representando a forca da comunidade nacional.\nThe Developers Conference (TDC) O TDC é um dos maiores eventos de tecnologia do Brasil e sempre tem trilhas dedicadas a Kotlin e Android. E uma excelente oportunidade para:\nAssistir palestras de qualidade Fazer networking presencial Conhecer empresas que usam Kotlin DevFest e GDG Events Os Google Developer Groups (GDGs) espalhados pelo Brasil organizam eventos regulares com conteudo Kotlin. DevFests acontecem em diversas cidades e frequentemente incluem talks sobre Kotlin, Android e Compose.\nMeetups Locais Meetups menores é mais frequentes acontecem em diversas cidades:\nSão Paulo: Meetups mensais com participacao expressiva Rio de Janeiro: Comunidade ativa com eventos regulares Belo Horizonte: Crescente cena de Kotlin Curitiba: Comunidade técnica forte com interesse em Kotlin Florianopolis: Polo tecnologico com muitas empresas usando Kotlin Como Contribuir para a Comunidade Escrevendo Conteudo Produzir conteudo em português sobre Kotlin é uma das formas mais impactantes de contribuir:\n// Compartilhar dicas praticas ajuda a comunidade // Exemplo: \u0026#34;Você sabia que pode usar require e check para validacoes?\u0026#34; fun processarPedido(pedido: Pedido) { // require - Valida argumentos de entrada require(pedido.itens.isNotEmpty()) { \u0026#34;Pedido deve ter pelo menos um item\u0026#34; } require(pedido.valor \u0026gt; 0) { \u0026#34;Valor do pedido deve ser positivo\u0026#34; } // check - Valida estado do objeto check(pedido.status == PedidoStatus.RASCUNHO) { \u0026#34;Apenas pedidos em rascunho podem ser processados\u0026#34; } // Processar... } Plataformas para publicar:\nDev.to: Grande audiencia brasileira Medium: Boa visibilidade para conteudo técnico Blog pessoal: Controle total sobre o conteudo LinkedIn: Artigos alcancam recrutadores e profissionais Palestras e Talks Compartilhar conhecimento em eventos e extremamente valorizado:\nComece pequeno: Lightning talks de 5-10 minutos em meetups locais Prepare bem: Slides claros, demonstracoes práticas, código ao vivo Grave e compartilhe: Disponibilize no YouTube para alcance maior Evolua: Com experiência, submeta talks para conferencias maiores Contribuicao Open Source Contribuir para projetos open source em Kotlin e uma forma poderosa de participar da comunidade global:\n// Contribuicoes podem ser simples e valiosas // Exemplo: Melhorar documentacao de uma biblioteca /** * Converte uma lista de [Product] para uma lista de [ProductDTO]. * * Esta funcao e util quando voce precisa transformar modelos de dominio * em objetos de transferencia para APIs REST. * * Exemplo de uso: * ```kotlin * val produtos = repository.findAll() * val dtos = produtos.toDTO() * ``` * * @return Lista de [ProductDTO] correspondente * @see ProductDTO */ fun List\u0026lt;Product\u0026gt;.toDTO(): List\u0026lt;ProductDTO\u0026gt; { return map { product -\u0026gt; ProductDTO( id = product.id, nome = product.nome, preco = product.preco.toReais() ) } } Projetos para contribuir:\nKotlin: A própria linguagem aceita contribuicoes Ktor: Framework web da JetBrains Exposed: ORM nativo Kotlin Kotest: Framework de testes Arrow: Programação funcional em Kotlin Mentoria Se você já tem experiência, mentorar iniciantes e uma contribuicao inestimavel:\nResponda perguntas nos grupos online com paciencia Ofereca revisao de código para quem esta aprendendo Crie tutoriais passo a passo Participe como mentor em programas formais Empresas Brasileiras Que Usam Kotlin Conhecer empresas que usam Kotlin ajuda tanto na busca de emprego quanto no networking:\nFintechs e Bancos Nubank: Um dos maiores usuários de Kotlin no Brasil, tanto mobile quanto backend PicPay: Forte uso de Kotlin para Android e microsserviços Itau: Migração progressiva de Java para Kotlin Inter: Kotlin para mobile e backend Stone: Stack Kotlin moderna Tecnologia e Startups iFood: Kotlin no Android e backend MercadoLivre: Adoção crescente de Kotlin QuintoAndar: App Android em Kotlin com Compose Loft: Stack moderna com Kotlin Consultorias Thoughtworks: Projetos Kotlin para diversos clientes CI\u0026amp;T: Desenvolvimento mobile e backend com Kotlin Concrete (Accenture): Forte expertise em Android/Kotlin Recursos de Aprendizado em Português A comunidade brasileira produz conteudo de qualidade:\nCursos e Tutoriais Kotlin Academy (parcialmente traduzido) Canais YouTube brasileiros focados em Android/Kotlin Cursos na Udemy e Alura em português Livros e Documentação Documentação oficial do Kotlin (parcialmente em português) Artigos traduzidos pela comunidade Blog posts de desenvolvedores brasileiros Dicas para Aproveitar ao Maximo a Comunidade Seja ativo, não passivo: Participe de discussoes, responda perguntas, compartilhe experiencias\nNao tenha medo de perguntar: A comunidade Kotlin brasileira e conhecida por ser acolhedora. Perguntas de iniciantes são bem-vindas\nCompartilhe suas vitorias: Terminou um projeto? Aprendeu algo novo? Compartilhe nos grupos\nConecte-se pessoalmente: Networking presencial em eventos cria vinculos que grupos online não conseguem\nContribua de volta: Aprendeu algo com a comunidade? Retribua ensinando\nSeja consistente: Participacao regular constroi reputacao e relacionamentos\nConclusão A comunidade Kotlin no Brasil e um ecossistema rico e acolhedor, cheio de oportunidades para aprendizado, networking e crescimento profissional. Independente do seu nível de experiência, há espaco para você contribuir e se beneficiar.\nParticipe dos grupos online, va a eventos presenciais, escreva conteudo, contribua para projetos open source e ajude outros desenvolvedores. A comunidade e feita de pessoas, e quanto mais você se envolve, mais recebe de volta. O Kotlin Brasil esta aqui para conectar, educar e fortalecer a comunidade de desenvolvedores Kotlin em todo o pais. Confira também as comunidades brasileiras de Go, Rust e Python — networking multilinguagem enriquece sua carreira.\n","permalink":"https://kotlin.dev.br/blog/comunidade-kotlin-brasil/","summary":"\u003cp\u003eA comunidade Kotlin no Brasil esta vibrante e em pleno crescimento. De grupos no Telegram a conferencias presenciais, há inumeras formas de se conectar com outros desenvolvedores, aprender e contribuir. Neste artigo, vamos mapear toda a comunidade Kotlin brasileira e te mostrar como fazer parte dela.\u003c/p\u003e\n\u003ch2 id=\"o-estado-da-comunidade-kotlin-no-brasil\"\u003eO Estado da Comunidade Kotlin no Brasil\u003c/h2\u003e\n\u003cp\u003eO Brasil é um dos maiores mercados de desenvolvimento mobile do mundo, e com Kotlin sendo a linguagem oficial do Android, a comunidade cresceu organicamente. Mas o ecossistema vai muito além do mobile: desenvolvedores backend, multiplatform e até web contribuem para uma comunidade diversa e acolhedora.\u003c/p\u003e","title":"Comunidade Kotlin no Brasil: Grupos, Eventos e Como Participar | Kotlin Brasil"},{"content":"O que é expect/actual em Kotlin? As palavras-chave expect e actual são o mecanismo do Kotlin Multiplatform (KMP) para declarar APIs no código comum e fornecer implementacoes específicas para cada plataforma. O expect define o contrato no modulo compartilhado, é o actual fornece a implementação concreta em cada plataforma (JVM, iOS, JavaScript, etc.).\nE como um contrato: o modulo comum diz \u0026ldquo;eu preciso desta funcionalidade\u0026rdquo;, e cada plataforma responde \u0026ldquo;aqui esta como eu implemento\u0026rdquo;.\nO problema que expect/actual resolve Quando você escreve código multiplataforma, a maioria da lógica pode ser compartilhada. Porem, algumas funcionalidades dependem da plataforma: acesso ao sistema de arquivos, criptografia, formatação de datas, acesso a rede nativa. O expect/actual permite que o código comum use essas funcionalidades sem conhecer a implementação específica.\nSintaxe básica No modulo commonMain (código compartilhado):\n// commonMain/src/Platform.kt expect fun plataformaAtual(): String expect class DataFormatada(timestamp: Long) { fun formatar(): String } No modulo jvmMain (implementação JVM):\n// jvmMain/src/Platform.kt actual fun plataformaAtual(): String = \u0026#34;JVM ${System.getProperty(\u0026#34;java.version\u0026#34;)}\u0026#34; actual class DataFormatada actual constructor(private val timestamp: Long) { actual fun formatar(): String { val sdf = java.text.SimpleDateFormat(\u0026#34;dd/MM/yyyy HH:mm\u0026#34;) return sdf.format(java.util.Date(timestamp)) } } No modulo iosMain (implementação iOS):\n// iosMain/src/Platform.kt import platform.UIKit.UIDevice actual fun plataformaAtual(): String = UIDevice.currentDevice.systemName() + \u0026#34; \u0026#34; + UIDevice.currentDevice.systemVersion actual class DataFormatada actual constructor(private val timestamp: Long) { actual fun formatar(): String { val formatter = platform.Foundation.NSDateFormatter() formatter.dateFormat = \u0026#34;dd/MM/yyyy HH:mm\u0026#34; val date = platform.Foundation.NSDate(timeIntervalSince1970 = timestamp / 1000.0) return formatter.stringFromDate(date) } } O que pode ser expect/actual Você pode usar expect/actual com vários tipos de declaracoes:\n// Funções expect fun gerarUUID(): String // Classes expect class HttpClient() { suspend fun get(url: String): String } // Objetos expect object Configuração { val versao: String val debug: Boolean } // Propriedades top-level expect val diretorioTemporario: String // Anotações expect annotation class Parcelize() // Type aliases (actual pode ser typealias) expect class BigDecimalMultiplatform // No JVM: actual typealias BigDecimalMultiplatform = java.math.BigDecimal Exemplo completo: armazenamento de preferencias Um caso de uso real e compartilhar a interface de armazenamento entre plataformas:\n// commonMain expect class PreferenciasStorage { fun salvar(chave: String, valor: String) fun ler(chave: String): String? fun remover(chave: String) } // Uso no codigo comum class RepositorioDeConfiguracoes(private val storage: PreferenciasStorage) { fun salvarTema(tema: String) = storage.salvar(\u0026#34;tema\u0026#34;, tema) fun obterTema(): String = storage.ler(\u0026#34;tema\u0026#34;) ?: \u0026#34;claro\u0026#34; } // androidMain import android.content.SharedPreferences actual class PreferenciasStorage(private val prefs: SharedPreferences) { actual fun salvar(chave: String, valor: String) { prefs.edit().putString(chave, valor).apply() } actual fun ler(chave: String): String? = prefs.getString(chave, null) actual fun remover(chave: String) { prefs.edit().remove(chave).apply() } } // iosMain import platform.Foundation.NSUserDefaults actual class PreferenciasStorage { private val defaults = NSUserDefaults.standardUserDefaults actual fun salvar(chave: String, valor: String) { defaults.setObject(valor, forKey = chave) } actual fun ler(chave: String): String? = defaults.stringForKey(chave) actual fun remover(chave: String) { defaults.removeObjectForKey(chave) } } expect/actual com interfaces (alternativa moderna) Em muitos casos, usar expect/actual com interfaces e injeção de dependências e mais flexivel:\n// commonMain - definir interface interface Plataforma { val nome: String fun gerarId(): String } // commonMain - declarar expect para obter a implementacao expect fun criarPlataforma(): Plataforma // jvmMain actual fun criarPlataforma(): Plataforma = object : Plataforma { override val nome = \u0026#34;JVM\u0026#34; override fun gerarId() = java.util.UUID.randomUUID().toString() } // iosMain actual fun criarPlataforma(): Plataforma = object : Plataforma { override val nome = \u0026#34;iOS\u0026#34; override fun gerarId() = platform.Foundation.NSUUID().UUIDString() } Essa abordagem combina o mecanismo expect/actual com polimorfismo, facilitando testes com implementacoes fake.\nConfiguração do projeto A estrutura de diretorios de um projeto KMP com expect/actual tipicamente e:\nsrc/ commonMain/kotlin/ \u0026lt;- expect declarations commonTest/kotlin/ \u0026lt;- testes compartilhados jvmMain/kotlin/ \u0026lt;- actual JVM iosMain/kotlin/ \u0026lt;- actual iOS jsMain/kotlin/ \u0026lt;- actual JavaScript Quando usar expect/actual APIs de plataforma: quando você precisa acessar funcionalidades específicas do SO (arquivos, rede nativa, sensores). Bibliotecas nativas: quando cada plataforma tem sua própria biblioteca para a mesma funcionalidade. Otimizações específicas: quando a implementação ideal difere entre plataformas. Integracoes de UI: quando componentes visuais são diferentes em cada plataforma. Prefira código comum puro sempre que possível. Use expect/actual apenas quando realmente houver diferenca entre plataformas.\nCasos de Uso no Mundo Real Armazenamento local multiplataforma: aplicações KMP usam expect/actual para abstrair o armazenamento de dados. No Android, a implementação actual usa SharedPreferences ou DataStore; no iOS, usa NSUserDefaults; na web, usa localStorage. O código comum define a interface de leitura e escrita sem conhecer os detalhes de cada plataforma.\nCriptografia e seguranca: bibliotecas multiplataforma de criptografia declaram funções expect para hashing, encriptacao e geracao de chaves. Cada plataforma fornece a implementação actual usando suas APIs nativas (java.security no JVM, CommonCrypto no iOS, Web Crypto API no JavaScript), garantindo performance e conformidade com padrões de seguranca nativos.\nAcesso a funcionalidades de hardware: aplicações que precisam acessar GPS, camera ou sensores declaram interfaces expect no código comum. As implementacoes actual em cada plataforma usam as APIs nativas correspondentes (LocationManager no Android, CLLocationManager no iOS), permitindo que a lógica de negócio permaneca no modulo compartilhado.\nFormatacao e internacionalizacao: a formatacao de datas, números e moedas depende de APIs especificas de cada plataforma. O expect/actual permite declarar funções de formatacao no commonMain e implementa-las com java.text.DateFormat no JVM, NSDateFormatter no iOS e Intl.DateTimeFormat no JavaScript.\nBoas Praticas Mantenha as declaracoes actual o mais finas possível, contendo apenas o código que realmente depende da plataforma. Toda lógica de negócio e validacao deve ficar no commonMain, onde pode ser testada uma única vez. Prefira usar interfaces combinadas com funções factory expect/actual em vez de classes expect inteiras. Isso facilita a criação de implementacoes fake para testes e permite maior flexibilidade na injecao de dependências. Use actual typealias quando a plataforma já possui um tipo que atende exatamente ao contrato do expect. Isso evita a criação de wrappers desnecessários e melhora a interoperabilidade com código nativo. Escreva testes no commonTest que validem o contrato definido pelas declaracoes expect, e testes adicionais em cada source set de plataforma para verificar comportamentos específicos das implementacoes actual. Avalie se a funcionalidade realmente precisa de expect/actual ou se pode ser resolvida com uma biblioteca multiplataforma existente (como kotlinx-datetime para datas ou Ktor para rede). Nem tudo que parece específico de plataforma requer implementação manual. Perguntas Frequentes P: O que acontece se eu esquecer de criar a implementação actual em uma plataforma? R: O compilador emite um erro durante a compilação da plataforma que não possui a implementação actual. O projeto não compila até que todas as declaracoes expect tenham seus correspondentes actual em cada plataforma alvo configurada no build.\nP: Posso ter lógica diferente na implementação actual de cada plataforma? R: Sim, desde que a assinatura (nome, parametros, tipo de retorno e visibilidade) corresponda exatamente a declaracao expect. A implementação interna pode ser completamente diferente em cada plataforma. Essa e justamente a finalidade do mecanismo: mesmo contrato, implementacoes distintas.\nP: Qual a diferenca entre usar expect/actual e interfaces com injecao de dependência? R: O expect/actual e resolvido em tempo de compilação pelo compilador Kotlin, enquanto interfaces com DI sao resolvidas em tempo de execução. O expect/actual e mais adequado para funções e tipos que precisam existir em cada plataforma sem overhead de runtime. Interfaces com DI sao mais flexiveis para testes e configuração dinâmica.\nP: Posso usar expect/actual em projetos que não sao Kotlin Multiplatform? R: Nao. As palavras-chave expect e actual sao exclusivas do Kotlin Multiplatform e só funcionam em projetos configurados com o plugin kotlin-multiplatform. Em projetos single-platform, use interfaces e implementacoes convencionais.\nErros comuns Esquecer de implementar actual em alguma plataforma: o compilador reclama, mas o erro pode ser confuso se você tem muitos source sets. Verifique que toda declaracao expect tem um actual correspondente em cada plataforma alvo.\nDivergir a assinatura entre expect e actual: os parametros, tipos de retorno e modificadores de visibilidade devem corresponder exatamente.\nUsar expect/actual quando interfaces bastam: se a funcionalidade pode ser abstraida com uma interface e injeção de dependência, essa abordagem e mais testavel e flexivel.\nColocar lógica de negócio no actual: o actual deve conter apenas o minimo necessário de código específico da plataforma. Logica de negócio pertence ao commonMain.\nNao testar cada plataforma: testes no commonTest validam o contrato, mas você também precisa de testes em cada plataforma para garantir que as implementacoes actual funcionam corretamente.\nTermos relacionados Kotlin Multiplatform (KMP): o framework que permite compartilhar código Kotlin entre JVM, iOS, JavaScript e outras plataformas. Source Set: conjunto de arquivos fonte específicos de uma plataforma ou compartilhados. commonMain: source set do código compartilhado entre todas as plataformas. Type Alias: actual typealias permite mapear uma declaracao expect para um tipo existente da plataforma. Gradle Plugin: o plugin kotlin-multiplatform configura a compilação para múltiplas plataformas. Serialization: a biblioteca kotlinx.serialization usa expect/actual internamente para serializar em diferentes plataformas. O mecanismo expect/actual e a espinha dorsal do Kotlin Multiplatform, permitindo que você compartilhe a maior parte do código enquanto respeita as particularidades de cada plataforma. E um equilibrio elegante entre reutilização e especializacao.\n","permalink":"https://kotlin.dev.br/glossario/expect-actual/","summary":"\u003ch2 id=\"o-que-é-expectactual-em-kotlin\"\u003eO que é expect/actual em Kotlin?\u003c/h2\u003e\n\u003cp\u003eAs palavras-chave \u003cstrong\u003e\u003ccode\u003eexpect\u003c/code\u003e\u003c/strong\u003e e \u003cstrong\u003e\u003ccode\u003eactual\u003c/code\u003e\u003c/strong\u003e são o mecanismo do \u003cstrong\u003eKotlin Multiplatform (KMP)\u003c/strong\u003e para declarar APIs no código comum e fornecer implementacoes específicas para cada plataforma. O \u003ccode\u003eexpect\u003c/code\u003e define o contrato no modulo compartilhado, é o \u003ccode\u003eactual\u003c/code\u003e fornece a implementação concreta em cada plataforma (JVM, iOS, JavaScript, etc.).\u003c/p\u003e\n\u003cp\u003eE como um contrato: o modulo comum diz \u0026ldquo;eu preciso desta funcionalidade\u0026rdquo;, e cada plataforma responde \u0026ldquo;aqui esta como eu implemento\u0026rdquo;.\u003c/p\u003e","title":"Expect/Actual em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é emit em Kotlin? A função emit é o mecanismo principal para enviar valores dentro de um Flow em Kotlin. Quando você cria um Flow usando o builder flow { }, cada chamada a emit(valor) envia um novo valor para o coletor (quem esta consumindo o Flow).\nPense no emit como o momento em que você coloca um item na esteira de producao. Do outro lado, o collect pega cada item conforme ele chega. Essa dinâmica de produtor-consumidor é a essencia do Flow.\nSintaxe básica import kotlinx.coroutines.flow.* import kotlinx.coroutines.* fun numeros(): Flow\u0026lt;Int\u0026gt; = flow { emit(1) emit(2) emit(3) } fun main() = runBlocking { numeros().collect { valor -\u0026gt; println(\u0026#34;Recebido: $valor\u0026#34;) } } // Saida: // Recebido: 1 // Recebido: 2 // Recebido: 3 Cada emit e uma função suspend, o que significa que ela pode pausar a execução do produtor até que o consumidor esteja pronto para receber o proximo valor.\nemit e uma função suspend O fato de emit ser suspend e fundamental para o comportamento do Flow:\nfun dadosComDelay(): Flow\u0026lt;String\u0026gt; = flow { emit(\u0026#34;Carregando...\u0026#34;) delay(1000) emit(\u0026#34;Dados parciais\u0026#34;) delay(1000) emit(\u0026#34;Dados completos\u0026#34;) } fun main() = runBlocking { dadosComDelay().collect { status -\u0026gt; println(\u0026#34;$status - ${System.currentTimeMillis()}\u0026#34;) } } O produtor pode suspender entre emissoes (usando delay ou outras funções suspend), e o consumidor recebe cada valor conforme ele e emitido. Isso cria um fluxo natural de dados ao longo do tempo.\nEmitindo em loops Um padrão comum e emitir valores dentro de um loop:\nfun contagem(de: Int, ate: Int): Flow\u0026lt;Int\u0026gt; = flow { for (i in de..ate) { delay(500) emit(i) } } fun fibonacci(): Flow\u0026lt;Long\u0026gt; = flow { var a = 0L var b = 1L while (true) { emit(a) val temp = a + b a = b b = temp } } fun main() = runBlocking { // Pegar os 10 primeiros Fibonacci fibonacci().take(10).collect { println(it) } } O Flow e lazy: o loop infinito em fibonacci() não e um problema porque take(10) cancela o Flow apos coletar 10 valores.\nEmitindo a partir de fontes externas O emit pode ser chamado apos receber dados de qualquer fonte:\nfun monitorarArquivo(caminho: String): Flow\u0026lt;String\u0026gt; = flow { val arquivo = java.io.File(caminho) var ultimaModificacao = 0L while (true) { val modificacao = arquivo.lastModified() if (modificacao != ultimaModificacao) { ultimaModificacao = modificacao emit(arquivo.readText()) } delay(1000) } } fun leiturasDeSensor(): Flow\u0026lt;Double\u0026gt; = flow { val random = java.util.Random() while (true) { val leitura = 20.0 + random.nextDouble() * 10.0 emit(leitura) delay(500) } } Restricoes do emit O emit tem uma restricao importante: não pode ser chamado de um contexto concorrente. Dentro de um flow { }, você não pode emitir de outra coroutine:\n// ERRADO: emit de contexto concorrente fun fluxoErrado(): Flow\u0026lt;Int\u0026gt; = flow { coroutineScope { launch { emit(1) // IllegalStateException em tempo de execucao! } } } // CORRETO: usar channelFlow para emissao concorrente fun fluxoConcorrente(): Flow\u0026lt;Int\u0026gt; = channelFlow { launch { send(1) // OK: channelFlow suporta concorrência } launch { send(2) } } Se você precisa emitir valores de múltiplas coroutines, use channelFlow com send em vez de flow com emit.\nemit com transformacoes Operadores como transform permitem emitir múltiplos valores para cada valor de entrada:\nfun main() = runBlocking { val numeros = flowOf(1, 2, 3) numeros.transform { valor -\u0026gt; emit(\u0026#34;Processando $valor...\u0026#34;) delay(300) emit(\u0026#34;Resultado: ${valor * valor}\u0026#34;) }.collect { println(it) } } // Saida: // Processando 1... // Resultado: 1 // Processando 2... // Resultado: 4 // Processando 3... // Resultado: 9 O operador transform e a base sobre a qual map e filter são construidos. Ele da liberdade total sobre quantos valores emitir para cada valor recebido.\nBackpressure e emit O emit naturalmente implementa backpressure. Se o coletor for mais lento que o produtor, o emit suspende até que o coletor esteja pronto:\nfun produtorRapido(): Flow\u0026lt;Int\u0026gt; = flow { for (i in 1..5) { println(\u0026#34;Emitindo $i\u0026#34;) emit(i) } } fun main() = runBlocking { produtorRapido().collect { valor -\u0026gt; delay(1000) // Coletor lento println(\u0026#34;Coletado: $valor\u0026#34;) } } // A emissao espera o coletor processar antes de continuar Para cenários onde você quer descartar valores ou usar buffer, existem operadores como buffer, conflate e collectLatest.\nQuando usar emit Producao de dados sob demanda: quando os dados são gerados dinamicamente e precisam ser consumidos um por vez. Streams de eventos: monitoramento de arquivos, sensores, WebSockets. Transformacoes complexas: quando você precisa emitir múltiplos valores derivados de um único valor de entrada. Conversao de callbacks para Flow: dentro de callbackFlow, você usa trySend (similar ao emit) para converter APIs baseadas em callback para Flow. Casos de Uso no Mundo Real Monitoramento de dados em tempo real: aplicações que exibem dashboards com metricas ao vivo (preco de acoes, temperatura de servidores, status de sistemas) utilizam emit dentro de loops com delay para publicar atualizações periodicas. O Flow gerenciado com emit permite que a UI reaja a cada novo valor sem polling manual.\nUpload de arquivos com progresso: durante o upload de arquivos grandes, o emit e usado para publicar o percentual de progresso. Um Flow emite valores de 0 a 100 conforme os chunks sao enviados, permitindo que a camada de apresentação atualize uma barra de progresso de forma reativa.\npaginação de APIs: ao buscar dados paginados de uma API REST, o emit publica cada pagina de resultados conforme ela e carregada. O consumidor pode processar e exibir os dados incrementalmente sem esperar que todas as paginas sejam carregadas.\nConversao de callbacks legados para Flow: em projetos que migram de APIs baseadas em callback (como listeners do Firebase ou eventos de sensores do Android), o emit (via callbackFlow e trySend) e o mecanismo que transforma esses callbacks em streams reativos compativeis com a arquitetura moderna baseada em coroutines.\nBoas Praticas Mantenha a lógica de emissao simples e focada na producao de dados. Transformacoes complexas devem ser feitas com operadores do Flow (map, filter, transform) em vez de lógica condicional elaborada antes de cada emit. Use channelFlow com send em vez de flow com emit quando precisar emitir valores de múltiplas coroutines concorrentes. Tentar emitir de contextos concorrentes dentro de flow {} causa exceção em tempo de execução. Trate exceções que possam ocorrer antes do emit usando o operador catch no pipeline do Flow, em vez de try-catch dentro do builder. Isso mantém a separação entre producao e tratamento de erros. Ao emitir valores em loops infinitos (sensores, polling), sempre inclua um mecanismo de cancelamento cooperativo. O Flow já e cancelavel por natureza, mas certifique-se de que operações bloqueantes sejam interruptiveis. Evite efeitos colaterais dentro do builder flow {} que não estejam diretamente relacionados a producao de dados. Use o operador onEach no lado do consumo para acoes como logging e analytics. Perguntas Frequentes P: Posso chamar emit de dentro de uma coroutine lancada com launch ou async? R: Nao, dentro de um builder flow {}. O emit exige que a emissao seja sequencial e no mesmo contexto da coroutine do Flow. Se você precisa emitir de contextos concorrentes, use channelFlow com a função send em vez de flow com emit.\nP: O que acontece se o coletor for mais lento que o produtor? R: O emit implementa backpressure naturalmente: ele suspende a execução do produtor até que o coletor termine de processar o valor anterior. Para cenários onde você quer alterar esse comportamento, use operadores como buffer (para adicionar um buffer intermediario), conflate (para descartar valores intermediarios) ou collectLatest (para cancelar o processamento anterior quando um novo valor chega).\nP: Qual a diferenca entre emit e trySend em callbackFlow? R: O emit e uma função suspend usada dentro de flow {}, enquanto trySend e uma função não-suspend usada dentro de callbackFlow {}. O trySend e necessário em callbacks porque callbacks tradicionais não sao funções suspend. O trySend retorna um resultado indicando se o envio foi bem-sucedido, sem suspender a thread.\nP: Posso emitir null em um Flow? R: Sim, desde que o tipo do Flow permita nulos. Um Flow\u0026lt;String?\u0026gt; aceita emit(null) normalmente. O coletor recebera o valor null como qualquer outro valor emitido.\nErros comuns Chamar emit fora do flow builder: emit só pode ser chamado dentro do escopo do builder flow { } ou dentro de operadores como transform.\nEmitir de contexto concorrente: usar launch ou async dentro de flow { } e tentar emitir. Use channelFlow para isso.\nEsquecer que emit e suspend: tratar emit como uma operação instantanea quando na verdade ela pode suspender se o coletor estiver ocupado.\nNao tratar exceções: se uma exceção ocorre antes do emit, os valores já emitidos foram processados, mas os restantes serao perdidos. Use catch no Flow para tratamento adequado.\nConfundir emit com send: emit e para flow { }, send e para channelFlow { } e channels. Usar um no contexto do outro causa erro de compilação.\ncallbackFlow e trySend Para converter APIs baseadas em callback para Flow, use callbackFlow com trySend:\nfun eventosDeClique(botao: Botao): Flow\u0026lt;Unit\u0026gt; = callbackFlow { val listener = object : OnClickListener { override fun onClick() { trySend(Unit) } } botao.adicionarListener(listener) awaitClose { botao.removerListener(listener) } } Termos relacionados Flow: o tipo de stream reativo do Kotlin onde emit e a função principal de producao. collect: a função terminal que consome os valores emitidos por um Flow. channelFlow: builder de Flow que suporta emissao concorrente usando send. transform: operador que permite emitir múltiplos valores para cada valor de entrada. Coroutine: contexto de execução assíncrono onde Flows operam. suspend: modificador que permite que emit pause a execução quando necessário. O emit e o coracao do sistema de Flows em Kotlin. Entender como ele funciona, suas restricoes de concorrência e sua relação com backpressure e essencial para construir pipelines de dados reativos eficientes e corretos.\n","permalink":"https://kotlin.dev.br/glossario/emit/","summary":"\u003ch2 id=\"o-que-é-emit-em-kotlin\"\u003eO que é emit em Kotlin?\u003c/h2\u003e\n\u003cp\u003eA função \u003cstrong\u003e\u003ccode\u003eemit\u003c/code\u003e\u003c/strong\u003e é o mecanismo principal para \u003cstrong\u003eenviar valores\u003c/strong\u003e dentro de um \u003ccode\u003eFlow\u003c/code\u003e em Kotlin. Quando você cria um Flow usando o builder \u003ccode\u003eflow { }\u003c/code\u003e, cada chamada a \u003ccode\u003eemit(valor)\u003c/code\u003e envia um novo valor para o coletor (quem esta consumindo o Flow).\u003c/p\u003e\n\u003cp\u003ePense no \u003ccode\u003eemit\u003c/code\u003e como o momento em que você coloca um item na esteira de producao. Do outro lado, o \u003ccode\u003ecollect\u003c/code\u003e pega cada item conforme ele chega. Essa dinâmica de produtor-consumidor é a essencia do Flow.\u003c/p\u003e","title":"Emit em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Dispatcher em Kotlin? Um Dispatcher em Kotlin Coroutines determina em qual thread ou pool de threads uma coroutine sera executada. Ele é o mecanismo que conecta o mundo das coroutines ao mundo das threads do sistema operacional, decidindo onde o código realmente vai rodar.\nEscolher o dispatcher correto e fundamental para a performance é o comportamento da aplicação. Uma operação de rede executada no dispatcher errado pode travar a interface do usuário; um calculo pesado no dispatcher errado pode desperdicar recursos.\nOs dispatchers principais O Kotlin fornece quatro dispatchers padrões através do objeto Dispatchers:\nimport kotlinx.coroutines.* fun main() = runBlocking { // Dispatcher padrao para trabalho intensivo de CPU launch(Dispatchers.Default) { println(\u0026#34;Default: ${Thread.currentThread().name}\u0026#34;) } // Dispatcher para operacoes de I/O launch(Dispatchers.IO) { println(\u0026#34;IO: ${Thread.currentThread().name}\u0026#34;) } // Dispatcher da thread principal (Android/Swing/JavaFX) // launch(Dispatchers.Main) { ... } // Dispatcher sem confinamento - nao garante thread especifica launch(Dispatchers.Unconfined) { println(\u0026#34;Unconfined: ${Thread.currentThread().name}\u0026#34;) } } Dispatchers.Default O Dispatchers.Default usa um pool de threads compartilhado com tamanho igual ao número de nucleos da CPU (minimo 2). E otimizado para trabalho intensivo de CPU:\nsuspend fun calcularPrimos(ate: Int): List\u0026lt;Int\u0026gt; = withContext(Dispatchers.Default) { (2..ate).filter { numero -\u0026gt; (2..Math.sqrt(numero.toDouble()).toInt()).none { numero % it == 0 } } } fun main() = runBlocking { val primos = calcularPrimos(100_000) println(\u0026#34;Encontrados ${primos.size} primos\u0026#34;) } Use Dispatchers.Default para: algoritmos, processamento de dados, serialização/desserializacao, calculos matematicos.\nDispatchers.IO O Dispatchers.IO usa um pool de threads maior (padrão de 64 threads) projetado para operações de entrada e saida que bloqueiam a thread:\nsuspend fun lerArquivo(caminho: String): String = withContext(Dispatchers.IO) { java.io.File(caminho).readText() } suspend fun buscarDaApi(url: String): String = withContext(Dispatchers.IO) { java.net.URL(url).readText() } suspend fun consultarBanco(): List\u0026lt;String\u0026gt; = withContext(Dispatchers.IO) { // Simula consulta ao banco Thread.sleep(1000) listOf(\u0026#34;resultado1\u0026#34;, \u0026#34;resultado2\u0026#34;) } Use Dispatchers.IO para: leitura/escrita de arquivos, chamadas de rede, acesso a banco de dados, chamadas a APIs externas.\nDispatchers.Main O Dispatchers.Main executa na thread principal da aplicação. Em Android, e a thread de UI. Em aplicações desktop com Swing ou JavaFX, e a thread de eventos:\n// Android: atualizar UI apos buscar dados suspend fun carregarEExibir() { val dados = withContext(Dispatchers.IO) { repositorio.buscarDados() } // Volta para Main automaticamente textView.text = dados.toString() } Em Android com viewModelScope ou lifecycleScope, o dispatcher padrão já e Main, entao você só precisa mudar explicitamente quando for fazer I/O ou CPU.\nDispatchers.Unconfined O Dispatchers.Unconfined inicia a coroutine na thread do chamador, mas apos a primeira suspensao, retoma na thread que completou a operação suspensa:\nfun main() = runBlocking { launch(Dispatchers.Unconfined) { println(\u0026#34;Antes: ${Thread.currentThread().name}\u0026#34;) delay(100) println(\u0026#34;Depois: ${Thread.currentThread().name}\u0026#34;) // Pode ser outra thread! } } Use com extrema cautela. O Unconfined e útil em testes e casos muito específicos, mas pode causar comportamento imprevisivel em código de producao.\nwithContext: trocando de dispatcher A função withContext troca o dispatcher dentro de uma coroutine sem criar uma nova:\nsuspend fun processarDados(): String { // Busca dados em IO val dadosBrutos = withContext(Dispatchers.IO) { repositorio.buscarDados() } // Processa em Default val dadosProcessados = withContext(Dispatchers.Default) { dadosBrutos.map { transformar(it) } } return dadosProcessados.joinToString() } withContext e mais eficiente que launch + join porque não cria uma nova coroutine; apenas muda o contexto de execução.\nCriando dispatchers customizados Para cenários específicos, você pode criar seus próprios dispatchers:\n// Dispatcher com thread unica (util para acesso sequencial) val dispatcherDeBanco = newSingleThreadContext(\u0026#34;BancoDeDados\u0026#34;) // Dispatcher com pool fixo val dispatcherDeProcessamento = newFixedThreadPoolContext(4, \u0026#34;Processamento\u0026#34;) // Converter um Executor em dispatcher val meuExecutor = java.util.concurrent.Executors.newCachedThreadPool() val dispatcherCustom = meuExecutor.asCoroutineDispatcher() Lembre-se de fechar dispatchers customizados quando não forem mais necessários para evitar vazamento de threads:\ndispatcherDeBanco.close() dispatcherDeProcessamento.close() limitedParallelism A partir do Kotlin 1.6, você pode criar uma visao limitada de um dispatcher existente:\n// Limita IO a no maximo 4 threads para uma operacao especifica val dispatcherLimitado = Dispatchers.IO.limitedParallelism(4) suspend fun processarArquivos(arquivos: List\u0026lt;String\u0026gt;) = coroutineScope { arquivos.map { arquivo -\u0026gt; async(dispatcherLimitado) { lerEProcessar(arquivo) } }.awaitAll() } Isso e útil para evitar que uma operação consuma todas as threads do pool de I/O, deixando outras operações sem recursos.\nQuando usar cada dispatcher Dispatcher Uso Exemplos Default CPU intensivo Calculos, parsing, serialização IO Bloqueio de I/O Rede, arquivos, banco de dados Main UI Atualizar tela, mostrar dialogo Unconfined Testes Testes unitarios simples Casos de Uso no Mundo Real aplicações Android com chamadas de API: em apps Android, o padrão mais comum e usar Dispatchers.IO para chamadas de rede e banco de dados, e Dispatchers.Main para atualizar a interface do usuário com os resultados. ViewModels tipicamente lancam coroutines no Main e trocam para IO com withContext quando necessário.\nServidores backend com Ktor ou Spring: em aplicações server-side, Dispatchers.IO e usado para operações de banco de dados e chamadas a servicos externos, enquanto Dispatchers.Default processa lógica de negócio intensiva como geracao de relatorios, compressao de dados ou transformacoes em lote.\nProcessamento de imagens e arquivos: aplicações que manipulam imagens ou processam grandes volumes de arquivos usam Dispatchers.Default para operações de CPU (redimensionamento, compressao) e Dispatchers.IO para leitura e escrita no disco, frequentemente combinados com limitedParallelism para controlar o uso de recursos.\nPipelines de dados em tempo real: sistemas que consomem dados de sensores, WebSockets ou filas de mensagens utilizam dispatchers customizados com newSingleThreadContext para garantir processamento sequencial e thread-safe, combinados com Dispatchers.Default para etapas de transformacao paralela.\nBoas Praticas Use withContext em vez de launch quando precisar apenas trocar de dispatcher e aguardar o resultado. Isso evita a criação desnecessaria de uma nova coroutine e mantém o fluxo sequencial. Encapsule a escolha do dispatcher dentro de funções suspend de repositórios e data sources, em vez de exigir que o chamador saiba qual dispatcher usar. Isso segue o princípio de responsabilidade única. Utilize limitedParallelism para controlar o grau de concorrencia em operações que acessam recursos limitados, como conexoes de banco de dados ou APIs com rate limiting. Evite Dispatchers.Unconfined em código de producao. Ele e útil para testes unitarios simples, mas em producao pode causar comportamento imprevisivel ao retomar a coroutine em threads inesperadas. Injete dispatchers como dependência em classes que os utilizam, permitindo que testes substituam por TestDispatcher para execução deterministica e controlada. Perguntas Frequentes P: Qual a diferenca entre Dispatchers.Default e Dispatchers.IO? R: O Dispatchers.Default usa um pool de threads limitado ao número de nucleos da CPU e e otimizado para trabalho computacional intensivo. O Dispatchers.IO usa um pool maior (até 64 threads por padrão) e e projetado para operações que bloqueiam a thread, como leitura de arquivos ou chamadas de rede. Usar o dispatcher errado pode causar problemas de performance: CPU intensivo no IO desperdiça context switching, e I/O bloqueante no Default pode esgotar os poucos threads disponiveis.\nP: Preciso sempre especificar um dispatcher ao lancar uma coroutine? R: Nao. Se você não especificar, a coroutine herda o dispatcher do escopo pai. Em Android com viewModelScope, o dispatcher padrão e Dispatchers.Main. Em runBlocking, e o dispatcher da thread que chamou. Especifique um dispatcher apenas quando precisar de comportamento diferente do herdado.\nP: Como escolher entre criar um dispatcher customizado e usar limitedParallelism? R: Prefira limitedParallelism na maioria dos casos, pois ele reutiliza threads do pool existente sem criar threads extras. Crie dispatchers customizados apenas quando precisar de isolamento total de threads, como em operações que exigem thread-local storage ou acesso a bibliotecas nativas que não sao thread-safe.\nP: E seguro compartilhar o mesmo dispatcher entre diferentes partes da aplicação? R: Sim, os dispatchers padrão (Default, IO, Main) sao projetados para uso compartilhado global. Para dispatchers customizados, o compartilhamento e seguro desde que você gerencie o ciclo de vida corretamente e feche o dispatcher quando a aplicação não precisar mais dele.\nErros comuns Fazer I/O no Dispatchers.Default: operações que bloqueiam a thread desperdicam os poucos threads do pool Default. Use IO para operações bloqueantes.\nAtualizar UI fora do Dispatchers.Main: em Android, acessar Views fora da main thread causa crash. Sempre volte para Main antes de atualizar a UI.\nUsar Dispatchers.IO para CPU: IO tem muitas threads, o que é desperdicio para trabalho de CPU. O excesso de context switching reduz a performance.\nCriar dispatchers customizados sem necessidade: os dispatchers padrões atendem a grande maioria dos casos. Crie customizados apenas quando tiver necessidades específicas de controle.\nNao fechar dispatchers customizados: dispatchers criados com newSingleThreadContext ou newFixedThreadPoolContext precisam ser fechados para liberar threads.\nConfundir withContext com launch: withContext suspende e retorna um resultado; launch cria uma coroutine que roda em paralelo. Use withContext para trocar de dispatcher e continuar sequencialmente.\nTermos relacionados Coroutine: unidade de execução leve que roda em um dispatcher específico. CoroutineContext: contexto que inclui o dispatcher, o Job e outros elementos. withContext: função que muda o dispatcher dentro de uma coroutine. launch/async: funções que criam novas coroutines, opcionalmente com um dispatcher específico. Job: elemento do contexto que representa o ciclo de vida da coroutine. Flow: streams reativos que podem mudar de dispatcher com flowOn. Dispatchers são o elo entre coroutines e threads. Entender quando e como usa-los e essencial para escrever código concorrente que seja eficiente e livre de bugs de threading.\n","permalink":"https://kotlin.dev.br/glossario/dispatcher/","summary":"\u003ch2 id=\"o-que-é-dispatcher-em-kotlin\"\u003eO que é Dispatcher em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUm \u003cstrong\u003eDispatcher\u003c/strong\u003e em Kotlin Coroutines determina \u003cstrong\u003eem qual thread ou pool de threads\u003c/strong\u003e uma coroutine sera executada. Ele é o mecanismo que conecta o mundo das coroutines ao mundo das threads do sistema operacional, decidindo onde o código realmente vai rodar.\u003c/p\u003e\n\u003cp\u003eEscolher o dispatcher correto e fundamental para a performance é o comportamento da aplicação. Uma operação de rede executada no dispatcher errado pode travar a interface do usuário; um calculo pesado no dispatcher errado pode desperdicar recursos.\u003c/p\u003e","title":"Dispatcher em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Context Receiver em Kotlin? Context Receivers são um recurso do Kotlin que permite declarar que uma função ou propriedade requer um ou mais contextos implícitos para ser chamada. Diferente de extension functions, que tem um único receiver, context receivers permitem que uma função dependa de múltiplos objetos de contexto sem precisar recebe-los como parametros explicitos.\nEsse recurso foi introduzido como experimental a partir do Kotlin 1.6.20 e continua evoluindo. Ele resolve um problema antigo: como expressar que uma função precisa de múltiplos \u0026ldquo;ambientes\u0026rdquo; para funcionar, sem poluir a assinatura com muitos parametros.\nO problema que Context Receivers resolvem Imagine que você tem uma função que precisa de acesso a um logger é a uma transacao de banco de dados. Sem context receivers, você teria estas opções:\n// Opcao 1: Parametros explicitos (verboso) fun salvarUsuario(usuario: Usuario, logger: Logger, transacao: Transacao) { logger.info(\u0026#34;Salvando usuario...\u0026#34;) transacao.executar { /* salvar */ } } // Opcao 2: Extension function (limitado a um receiver) fun Logger.salvarUsuario(usuario: Usuario, transacao: Transacao) { info(\u0026#34;Salvando usuario...\u0026#34;) transacao.executar { /* salvar */ } } Nenhuma dessas opções expressa claramente que a função depende de ambos os contextos. Com context receivers, a intencao fica explicita:\ncontext(Logger, Transacao) fun salvarUsuario(usuario: Usuario) { info(\u0026#34;Salvando usuario...\u0026#34;) executar { /* salvar */ } } Sintaxe e declaracao A sintaxe usa a palavra-chave context seguida dos tipos de contexto entre parenteses:\ncontext(LoggerContext) fun registrarEvento(mensagem: String) { log(\u0026#34;Evento: $mensagem\u0026#34;) } context(LoggerContext, MetricasContext) fun registrarComMetricas(mensagem: String) { log(\u0026#34;Evento: $mensagem\u0026#34;) incrementarContador(\u0026#34;eventos.registrados\u0026#34;) } Para chamar essas funções, você precisa estar em um escopo onde os contextos estejam disponiveis:\ninterface LoggerContext { fun log(mensagem: String) } interface MetricasContext { fun incrementarContador(nome: String) } fun main() { val logger = object : LoggerContext { override fun log(mensagem: String) = println(mensagem) } val métricas = object : MetricasContext { override fun incrementarContador(nome: String) = println(\u0026#34;$nome +1\u0026#34;) } with(logger) { with(métricas) { registrarComMetricas(\u0026#34;Usuario criado\u0026#34;) } } } Exemplo prático: DSL com múltiplos contextos Context receivers brilham na criação de DSLs onde diferentes escopos precisam estar disponiveis:\ninterface HtmlContext { fun tag(nome: String, conteudo: String) } interface CssContext { fun estilo(seletor: String, propriedade: String, valor: String) } context(HtmlContext, CssContext) fun componenteEstilizado(nome: String, texto: String) { estilo(\u0026#34;.$nome\u0026#34;, \u0026#34;color\u0026#34;, \u0026#34;blue\u0026#34;) estilo(\u0026#34;.$nome\u0026#34;, \u0026#34;font-weight\u0026#34;, \u0026#34;bold\u0026#34;) tag(\u0026#34;div class=\u0026#39;$nome\u0026#39;\u0026#34;, texto) } Isso permite que a função componenteEstilizado acesse tanto a API de HTML quanto a de CSS sem receber nenhum parametro adicional.\nContext Receivers em classes Você também pode usar context receivers em classes e propriedades:\ninterface Configuração { val maxTentativas: Int val timeout: Long } context(Configuração) class ServicoDeRetentativa { fun \u0026lt;T\u0026gt; executar(bloco: () -\u0026gt; T): T { var tentativa = 0 while (true) { try { return bloco() } catch (e: Exception) { tentativa++ if (tentativa \u0026gt;= maxTentativas) throw e Thread.sleep(timeout) } } } } context(Configuração) val tempoTotalMaximo: Long get() = maxTentativas * timeout Context Receivers vs Extension Functions A diferenca fundamental e a quantidade de receivers:\n// Extension function: um unico receiver fun String.formatarComoTitulo(): String { return this.split(\u0026#34; \u0026#34;).joinToString(\u0026#34; \u0026#34;) { it.replaceFirstChar { c -\u0026gt; c.uppercase() } } } // Context receiver + extension: múltiplos contextos context(Locale) fun String.formatarLocalizado(): String { return this.uppercase(this@Locale) } Extension functions são ideais quando a função e logicamente um \u0026ldquo;método\u0026rdquo; daquele tipo. Context receivers são para quando a função precisa de um ambiente/contexto para funcionar, mas não e um método do contexto.\nHabilitando context receivers Como o recurso ainda e experimental, você precisa habilita-lo no build.gradle.kts:\ntasks.withType\u0026lt;KotlinCompile\u0026gt; { kotlinOptions { freeCompilerArgs += \u0026#34;-Xcontext-receivers\u0026#34; } } Sem essa flag, o compilador não reconhecera a sintaxe context(...).\nQuando usar Context Receivers DSLs complexas: quando o DSL tem múltiplas camadas de contexto que precisam estar acessiveis simultaneamente. Injeção de dependências implicita: quando funções dependem de serviços ou configurações que deveriam estar \u0026ldquo;no ambiente\u0026rdquo; sem serem passados explicitamente. separação de concerns: quando você quer expressar que uma função depende de capacidades específicas (logging, métricas, transacao) sem acoplar a implementacoes concretas. Reducao de parametros: quando muitas funções no mesmo modulo compartilham os mesmos parametros de contexto. Evite usar quando a função tem apenas um contexto (use extension function) ou quando os parametros são dados, não ambientes (use parametros normais).\nCasos de Uso no Mundo Real Camadas de servico com logging e transacoes: em aplicações backend, funções de servico frequentemente precisam de acesso a um logger, a uma transacao de banco de dados e a um contexto de autenticação. Com context receivers, essas dependências ficam implicitas na assinatura da função, eliminando a repeticao de parametros em dezenas de métodos sem recorrer a injecao global.\nDSLs para geracao de documentos e relatorios: ao construir DSLs que geram HTML, PDF ou relatorios estruturados, diferentes partes do documento precisam de acesso simultaneo a contextos de formatacao, estilo e dados. Context receivers permitem que funções como adicionarTabela ou adicionarGrafico acessem tanto o contexto de layout quanto o de dados sem parametros extras.\nFrameworks de validacao com escopo: bibliotecas de validacao podem definir funções de regra que exigem um contexto de validacao. Regras como campoObrigatorio ou valorMinimo operam dentro de um ValidacaoContext que acumula erros, enquanto também acessam um LocalizacaoContext para traduzir mensagens. Context receivers tornam essa composicao de escopos natural.\nAPIs de teste com múltiplos ambientes: em frameworks de teste, funções auxiliares frequentemente precisam de acesso a um banco de dados de teste, um servidor mock e um contexto de assertivas. Context receivers permitem que funções como inserirDadosDeTeste ou verificarResposta declarem explicitamente de quais ambientes dependem, sem criar classes gigantes com todas as dependências.\nBoas Praticas Use context receivers para dependências de ambiente (logging, transacoes, configuração), não para dados de negócio. Dados que variam por chamada devem continuar como parametros explicitos para manter a clareza. Defina os contextos como interfaces, não como classes concretas. Isso facilita a criação de implementacoes de teste e respeita o princípio de inversao de dependência, desacoplando a função de implementacoes especificas. Evite acumular mais de tres context receivers em uma única função. Muitos contextos implicitos tornam difícil entender de onde vem cada método chamado e prejudicam a legibilidade do código. Documente claramente quais contextos sao necessários e por que. Como os contextos sao implicitos, leitores do código podem não entender imediatamente de onde vem um método. Um comentario breve ou documentação KDoc ajuda bastante. Lembre-se de que o recurso e experimental. Isole o uso de context receivers em modulos internos onde mudancas de API sao facilmente propagaveis, evitando expor context receivers em APIs publicas de bibliotecas. Perguntas Frequentes P: Context receivers substituem injecao de dependências como Koin ou Dagger? R: Nao. Context receivers resolvem a passagem implicita de contextos em tempo de compilação, enquanto frameworks de DI como Koin e Dagger resolvem a criação e o gerenciamento do ciclo de vida de dependências em tempo de execução. Eles sao complementares: você pode usar DI para criar as instancias e context receivers para disponibiliza-las implicitamente nas funções.\nP: Posso usar context receivers em producao se o recurso e experimental? R: Tecnicamente sim, mas com cautela. A sintaxe e o comportamento podem mudar em versões futuras do Kotlin. Se decidir usar, isole o uso em modulos internos e esteja preparado para refatorar quando a API estabilizar. Monitore as KEEPs (Kotlin Evolution and Enhancement Proposals) para acompanhar a direcao do recurso.\nP: Qual a diferenca entre context receivers e scope functions como with e run? R: Scope functions criam um escopo temporario onde this se refere a um objeto, mas isso e uma decisao do ponto de chamada. Context receivers sao parte da assinatura da função e verificados pelo compilador: a função só pode ser chamada quando todos os contextos declarados estao disponiveis. Scope functions sao mecanismo de chamada; context receivers sao mecanismo de declaracao.\nP: Como resolver ambiguidade quando dois context receivers tem métodos com o mesmo nome? R: Use a sintaxe de qualificacao explicita com this@NomeDoTipo para indicar de qual receiver você quer chamar o método. Por exemplo, se LoggerContext e MetricasContext ambos tem um método registrar, use this@LoggerContext.registrar() ou this@MetricasContext.registrar() para desambiguar.\nErros comuns Esquecer de habilitar a flag do compilador: sem -Xcontext-receivers, o código não compila e a mensagem de erro pode ser confusa.\nAbusar de context receivers: usar contextos para tudo transforma o código em algo difícil de rastrear. Se o leitor não consegue entender de onde vem um método, o código ficou implicito demais.\nAmbiguidade entre receivers: se dois contextos tem métodos com o mesmo nome, o compilador pode ter dificuldade em resolver qual usar. Use qualificadores explicitos nesses casos.\nIgnorar que e experimental: o recurso pode mudar em versões futuras do Kotlin. Use com cautela em código de producao e esteja preparado para adaptar.\nConfundir com scope functions: with, apply e run criam escopos de receiver, mas não são a mesma coisa que context receivers. Context receivers são verificados em tempo de compilação na assinatura da função.\nTermos relacionados Receiver: o objeto sobre o qual uma extension function opera, acessivel via this. Extension Function: função que adiciona comportamento a um tipo existente, usando um único receiver. DSL: Domain Specific Language, onde context receivers permitem criar APIs fluentes com múltiplos contextos. Scope Functions: let, run, with, apply, also \u0026ndash; funções que criam escopos temporarios de receiver. Inline: funções inline combinadas com context receivers podem eliminar overhead de criação de objetos. Context receivers representam uma evolução significativa na expressividade do Kotlin, permitindo que funções declarem suas dependências de contexto de forma clara e verificada pelo compilador. Embora ainda experimental, o recurso já mostra grande potencial para simplificar APIs e DSLs complexas.\n","permalink":"https://kotlin.dev.br/glossario/context-receiver/","summary":"\u003ch2 id=\"o-que-é-context-receiver-em-kotlin\"\u003eO que é Context Receiver em Kotlin?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eContext Receivers\u003c/strong\u003e são um recurso do Kotlin que permite declarar que uma função ou propriedade requer um ou mais \u003cstrong\u003econtextos implícitos\u003c/strong\u003e para ser chamada. Diferente de extension functions, que tem um único receiver, context receivers permitem que uma função dependa de múltiplos objetos de contexto sem precisar recebe-los como parametros explicitos.\u003c/p\u003e\n\u003cp\u003eEsse recurso foi introduzido como experimental a partir do Kotlin 1.6.20 e continua evoluindo. Ele resolve um problema antigo: como expressar que uma função precisa de múltiplos \u0026ldquo;ambientes\u0026rdquo; para funcionar, sem poluir a assinatura com muitos parametros.\u003c/p\u003e","title":"Context Receiver em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é crossinline em Kotlin? O modificador crossinline é usado em parametros lambda de funções inline para indicar que a lambda não pode usar non-local return. Ele e necessário quando a lambda inlineada sera executada em um contexto diferente do fluxo normal da função, como dentro de outra lambda, um objeto anonimo ou uma coroutine.\nPara entender crossinline, você primeiro precisa entender o que acontece com lambdas em funções inline é o conceito de non-local return.\nNon-local return: o contexto Quando uma função e marcada como inline, as lambdas passadas a ela podem usar return para sair da função chamadora (non-local return):\ninline fun executar(bloco: () -\u0026gt; Unit) { bloco() } fun main() { executar { println(\u0026#34;Antes do return\u0026#34;) return // Non-local return: sai de main() } println(\u0026#34;Isso nunca e impresso\u0026#34;) } Esse return sai de main(), não apenas da lambda. Isso e possível porque o compilador copia o corpo da lambda diretamente no local da chamada.\nO problema que crossinline resolve O non-local return só funciona quando a lambda e executada diretamente no fluxo da função inline. Se a lambda for passada para outro contexto (como um Runnable ou uma coroutine), o non-local return não faz sentido e pode causar comportamento indefinido:\n// Isso NAO compila sem crossinline inline fun executarEmThread(bloco: () -\u0026gt; Unit) { val runnable = Runnable { bloco() // A lambda e executada em outro contexto! } Thread(runnable).start() } O compilador reclama porque bloco pode conter um return que tentaria sair da função chamadora, mas a lambda esta sendo executada em outra thread. A solução e crossinline:\ninline fun executarEmThread(crossinline bloco: () -\u0026gt; Unit) { val runnable = Runnable { bloco() // Agora ok: crossinline impede non-local return } Thread(runnable).start() } fun main() { executarEmThread { println(\u0026#34;Executando em outra thread\u0026#34;) // return // Erro de compilacao! crossinline impede isso } } Como funciona internamente Com crossinline, o compilador ainda faz o inline do corpo da lambda (copiando o código), mas impede que return sem label seja usado. Você ainda pode usar return@executarEmThread (local return):\ninline fun processar(crossinline bloco: () -\u0026gt; Unit) { val wrapper = object : Runnable { override fun run() { bloco() } } wrapper.run() } fun main() { processar { println(\u0026#34;Processando...\u0026#34;) return@processar // Local return: permitido // return // Non-local return: proibido pelo crossinline } println(\u0026#34;Continua executando\u0026#34;) } Exemplo prático: builder com callback Um caso real onde crossinline e necessário e quando você cria builders que armazenam lambdas para execução posterior:\nclass EventoBuilder { private val acoes = mutableListOf\u0026lt;() -\u0026gt; Unit\u0026gt;() fun adicionarAcao(acao: () -\u0026gt; Unit) { acoes.add(acao) } fun executar() { acoes.forEach { it() } } } inline fun construirEvento(crossinline configuracao: EventoBuilder.() -\u0026gt; Unit): EventoBuilder { val builder = EventoBuilder() builder.configuracao() return builder } fun main() { val evento = construirEvento { adicionarAcao { println(\u0026#34;Acao 1\u0026#34;) } adicionarAcao { println(\u0026#34;Acao 2\u0026#34;) } } evento.executar() } Sem crossinline, se configuração contivesse um return, ele tentaria sair da função chamadora de construirEvento, o que não faz sentido quando o builder sera usado depois.\ncrossinline vs noinline Ambos lidam com restricoes em lambdas de funções inline, mas de formas diferentes:\ninline fun exemplo( crossinline lambdaCross: () -\u0026gt; Unit, // Inlineada, sem non-local return noinline lambdaNo: () -\u0026gt; Unit // NAO inlineada, tratada como objeto ) { val runnable1 = Runnable { lambdaCross() } // OK val runnable2 = Runnable { lambdaNo() } // OK // lambdaNo pode ser armazenada em variavel val referência: () -\u0026gt; Unit = lambdaNo // OK // val ref2: () -\u0026gt; Unit = lambdaCross // Erro! crossinline ainda e inlineada } A diferenca chave:\ncrossinline: a lambda ainda e inlineada (código copiado), mas sem non-local return. Nao pode ser armazenada como referência. noinline: a lambda não e inlineada, e tratada como um objeto Function normal. Pode ser armazenada, passada como parametro, etc. Quando usar crossinline Use crossinline quando:\nA função e inline e a lambda sera passada para outro contexto de execução (thread, coroutine, objeto anonimo). Você quer manter os beneficios de performance do inline (sem alocacao de objeto Function) mas precisa impedir non-local return. A lambda sera executada dentro de outra lambda não-inline ou callback. Na prática, o compilador vai te avisar quando crossinline e necessário. Se você tentar usar uma lambda inline em um contexto onde non-local return seria problematico, o compilador emite um erro sugerindo adicionar crossinline.\nCasos de Uso no Mundo Real Frameworks de injecao de dependência: bibliotecas como Koin usam funções inline com lambdas de configuração que sao armazenadas internamente. O crossinline garante que o código do usuário não tente fazer non-local return de dentro do builder de modulos, mantendo a integridade do ciclo de vida do framework.\nDSLs de construcao de UI: em frameworks como Jetpack Compose e bibliotecas de UI customizadas, lambdas de composicao sao passadas para contextos internos de renderizacao. O crossinline permite que essas lambdas sejam inlineadas para performance, sem permitir que um return interrompa o pipeline de renderizacao.\nWrappers de execução assíncrona: ao criar funções utilitarias que encapsulam o lancamento de coroutines ou execução em threads separadas, o crossinline e essencial para impedir que a lambda tente retornar da função chamadora quando esta sendo executada em outro contexto de thread.\nSistemas de eventos e callbacks: em arquiteturas orientadas a eventos, lambdas sao frequentemente registradas para execução futura. funções inline que registram esses handlers precisam de crossinline para manter os beneficios de performance do inline sem permitir non-local returns que não fariam sentido no momento da execução do evento.\nBoas Praticas Prefira crossinline em vez de noinline quando o único problema e o non-local return. Assim você mantém a otimização de inline (sem alocacao de objeto Function) e apenas restringe o tipo de return permitido. Deixe o compilador guiar você: na maioria dos casos, o compilador emitira um erro claro indicando que crossinline e necessário. Nao adicione o modificador preventivamente sem necessidade. Documente o motivo do crossinline na função com um comentario breve, especialmente em APIs publicas, para que outros desenvolvedores entendam por que a lambda não suporta non-local return. Ao projetar APIs inline com múltiplas lambdas, avalie cada parametro individualmente. Nem todas as lambdas precisam de crossinline; aplique apenas naquelas que serao executadas em outro contexto. Combine crossinline com contratos (contract) quando possível para preservar a capacidade do compilador de fazer smart casts mesmo com a restricao de return. Perguntas Frequentes P: Qual a diferenca entre crossinline e noinline na prática? R: O crossinline mantém o inline da lambda (o código e copiado no local da chamada, sem alocacao de objeto), mas impede non-local return. Ja o noinline faz com que a lambda seja tratada como um objeto Function normal, permitindo que seja armazenada em variaveis ou passada como argumento, porem sem os beneficios de performance do inline.\nP: O crossinline afeta a performance do código gerado? R: Nao negativamente. O crossinline mantém todos os beneficios de performance do inline. A única diferenca em relacao a uma lambda inline normal e a restricao de compilação que impede non-local return. O bytecode gerado e praticamente identico.\nP: Posso usar return com label dentro de uma lambda crossinline? R: Sim. O crossinline proibe apenas o non-local return (o return sem label que sairia da função chamadora). Voce ainda pode usar return@nomeDaFuncao para fazer um local return, que encerra apenas a execução da lambda.\nP: O compilador sempre avisa quando preciso usar crossinline? R: Sim, o compilador Kotlin detecta quando uma lambda inline e passada para um contexto onde non-local return seria inválido e emite um erro de compilação. A mensagem geralmente sugere adicionar crossinline ou noinline ao parametro.\nErros comuns Tentar usar return sem label em lambda crossinline: o compilador impede, mas iniciantes podem não entender o motivo do erro. Lembre-se de que crossinline proibe non-local return.\nConfundir crossinline com noinline: usar noinline quando crossinline seria suficiente desperdiça a otimização do inline. Se você só precisa impedir non-local return, use crossinline.\nUsar crossinline desnecessariamente: se a lambda e executada diretamente no fluxo da função inline, crossinline não e necessário e restringe sem motivo.\nNao entender quando o compilador exige crossinline: o erro do compilador pode parecer confuso. Sempre que você vir \u0026ldquo;can\u0026rsquo;t inline \u0026hellip; into \u0026hellip;\u0026rdquo;, considere adicionar crossinline ou noinline.\nEsquecer que crossinline não elimina o inline: a lambda ainda e copiada no local da chamada. Apenas o non-local return e impedido.\nExemplo com coroutines Um cenário moderno onde crossinline aparece e em funções que lancam coroutines:\ninline fun executarAsync( scope: CoroutineScope, crossinline bloco: suspend () -\u0026gt; Unit ) { scope.launch { bloco() // Executada em contexto de coroutine } } Sem crossinline, a lambda poderia tentar fazer non-local return da coroutine, o que não e válido.\nTermos relacionados inline: modificador que instrui o compilador a copiar o corpo da função no local da chamada. noinline: impede o inline de uma lambda específica, permitindo que seja tratada como objeto. Non-local return: capacidade de lambdas inline de retornar da função chamadora. Lambda: expressao funcional que pode ser passada como argumento, base do mecanismo de callbacks em Kotlin. Higher-Order Function: função que recebe ou retorna outra função. Coroutine: contexto assíncrono onde crossinline e frequentemente necessário. O crossinline e um daqueles recursos que você não usa todos os dias, mas quando precisa, e essencial. Ele permite que funções inline aproveitem a otimização de performance sem os riscos de non-local returns em contextos onde isso seria perigoso. O compilador do Kotlin e inteligente o suficiente para te avisar quando precisa dele.\n","permalink":"https://kotlin.dev.br/glossario/crossinline/","summary":"\u003ch2 id=\"o-que-é-crossinline-em-kotlin\"\u003eO que é crossinline em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO modificador \u003cstrong\u003e\u003ccode\u003ecrossinline\u003c/code\u003e\u003c/strong\u003e é usado em parametros lambda de funções \u003ccode\u003einline\u003c/code\u003e para indicar que a lambda \u003cstrong\u003enão pode usar non-local return\u003c/strong\u003e. Ele e necessário quando a lambda inlineada sera executada em um contexto diferente do fluxo normal da função, como dentro de outra lambda, um objeto anonimo ou uma coroutine.\u003c/p\u003e\n\u003cp\u003ePara entender \u003ccode\u003ecrossinline\u003c/code\u003e, você primeiro precisa entender o que acontece com lambdas em funções \u003ccode\u003einline\u003c/code\u003e é o conceito de non-local return.\u003c/p\u003e","title":"Crossinline em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Composable em Kotlin? Uma função Composable é uma função anotada com @Composable que descreve parte da interface do usuário no Jetpack Compose, o toolkit moderno de UI declarativa do Android. Em vez de montar telas com XML e manipular Views programaticamente, você escreve funções Kotlin que descrevem como a UI deve parecer para um dado estado.\nO Compose e inspirado em frameworks como React e Flutter, mas aproveita todo o poder do Kotlin: type safety, extension functions, coroutines é uma sintaxe concisa que faz a construcao de interfaces parecer natural.\nSintaxe básica import androidx.compose.runtime.Composable import androidx.compose.material3.Text @Composable fun Saudacao(nome: String) { Text(text = \u0026#34;Ola, $nome!\u0026#34;) } A anotacao @Composable informa ao compilador do Compose que essa função descreve UI e pode ser recomposta (re-executada) quando os dados mudam. Funções Composable só podem ser chamadas dentro de outros contextos Composable.\nComposição de funções O poder do Compose esta na composição. Você cria componentes pequenos e os combina para formar telas completas:\n@Composable fun CartaoDeUsuario(nome: String, email: String) { Column( modifier = Modifier .fillMaxWidth() .padding(16.dp) ) { Text( text = nome, style = MaterialTheme.typography.headlineSmall ) Spacer(modifier = Modifier.height(4.dp)) Text( text = email, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant ) } } @Composable fun ListaDeUsuarios(usuarios: List\u0026lt;Usuario\u0026gt;) { LazyColumn { items(usuarios) { usuario -\u0026gt; CartaoDeUsuario( nome = usuario.nome, email = usuario.email ) } } } Cada função Composable e um bloco reutilizavel. CartaoDeUsuario não sabe onde sera usado, e ListaDeUsuarios não sabe como o cartao e renderizado internamente. Essa separação torna o código modular e testavel.\nEstado em Composables Funções Composable são reexecutadas quando o estado muda. Para gerenciar estado local, use remember e mutableStateOf:\n@Composable fun Contador() { var contagem by remember { mutableStateOf(0) } Column(horizontalAlignment = Alignment.CenterHorizontally) { Text(text = \u0026#34;Contagem: $contagem\u0026#34;) Spacer(modifier = Modifier.height(8.dp)) Button(onClick = { contagem++ }) { Text(\u0026#34;Incrementar\u0026#34;) } } } Quando contagem muda, o Compose recompoe apenas as partes da UI que dependem desse valor. Isso e feito de forma inteligente pelo runtime do Compose, que rastreia quais Composables leem quais estados.\nRecomposicao Recomposicao e o processo pelo qual o Compose reexecuta funções Composable quando os dados de entrada mudam. E importante entender que:\nA recomposicao pode acontecer a qualquer momento e em qualquer ordem. Funções Composable devem ser idempotentes: chamar com os mesmos parametros deve produzir o mesmo resultado. Funções Composable não devem ter efeitos colaterais não controlados. // Correto: sem efeitos colaterais @Composable fun ExibirNome(nome: String) { Text(text = nome) } // Incorreto: efeito colateral na recomposicao @Composable fun ExibirNomeComLog(nome: String) { println(\u0026#34;Recompondo...\u0026#34;) // Pode ser chamado muitas vezes! Text(text = nome) } Para efeitos colaterais controlados, use APIs como LaunchedEffect, SideEffect e DisposableEffect.\nEfeitos colaterais controlados @Composable fun TelaDeDetalhes(userId: String) { var usuario by remember { mutableStateOf\u0026lt;Usuario?\u0026gt;(null) } LaunchedEffect(userId) { // Executa quando userId muda usuario = repositorio.buscarUsuario(userId) } usuario?.let { u -\u0026gt; Column { Text(text = u.nome) Text(text = u.email) } } } LaunchedEffect lanca uma coroutine que e cancelada e reiniciada quando a chave (userId) muda. Isso garante que efeitos colaterais sejam gerenciados corretamente no ciclo de vida do Composable.\nModifiers Modifiers são o mecanismo do Compose para decorar e configurar componentes:\n@Composable fun CartaoEstilizado() { Card( modifier = Modifier .fillMaxWidth() .padding(16.dp) .clickable { /* acao */ } ) { Text( text = \u0026#34;Conteudo do cartao\u0026#34;, modifier = Modifier.padding(24.dp) ) } } A ordem dos modifiers importa: padding antes de clickable produz resultado diferente de clickable antes de padding.\nQuando usar Composables Composables são usados em qualquer projeto Android que adote Jetpack Compose:\nTelas de aplicativos: construir layouts completos de forma declarativa. Componentes reutilizaveis: criar uma biblioteca de componentes de UI consistentes. Previews: usar @Preview para visualizar componentes no Android Studio sem rodar o app. Testes de UI: Composables são facilmente testáveis com a biblioteca de testes do Compose. Compose Multiplatform: o mesmo conceito funciona em desktop, web e iOS com Kotlin Multiplatform. Casos de Uso no Mundo Real Design systems corporativos: empresas criam bibliotecas de Composables reutilizaveis (botoes, campos de texto, cartoes, modais) que encapsulam regras de design e acessibilidade. Equipes de produto consomem esses componentes para garantir consistencia visual em dezenas de telas sem duplicar código de estilizacao.\nTelas de formularios dinâmicos: aplicações que renderizam formularios baseados em configuracoes do servidor (como cadastros, pesquisas ou checklists) usam Composables parametrizados que recebem a definicao dos campos e geram a interface automaticamente. Cada tipo de campo (texto, selecao, data) e um Composable independente composto pela tela pai.\nDashboards com gráficos e metricas: aplicações de analytics e monitoramento constroem paineis interativos usando Composables que reagem a mudancas de estado em tempo real. Graficos, indicadores e tabelas sao componentes Compose que se recompoem automaticamente quando os dados sao atualizados via Flow ou StateFlow do ViewModel.\naplicações multiplataforma com Compose Multiplatform: projetos que compartilham a mesma base de código Kotlin entre Android, desktop (Windows, macOS, Linux) e iOS usam Composables como a camada de UI unificada. Um mesmo componente de lista ou navegação funciona em todas as plataformas com adaptacoes minimas.\nBoas Praticas Aplique state hoisting por padrão: Composables devem receber o estado como parametro e emitir eventos via callbacks. Isso torna o componente stateless, reutilizavel e facilmente testavel com a biblioteca de testes do Compose. Mantenha Composables pequenos e focados em uma única responsabilidade. Um Composable que faz muita coisa (busca dados, processa lógica e renderiza UI) e difícil de testar e reutilizar. Delegue lógica de negócio ao ViewModel. Use @Preview com múltiplas configuracoes (temas claro e escuro, diferentes tamanhos de tela, dados de exemplo variados) para validar a aparencia do componente sem precisar compilar e executar o aplicativo inteiro. Evite efeitos colaterais diretos dentro de Composables. Use LaunchedEffect para coroutines, SideEffect para código sincrono que precisa executar apos a composicao e DisposableEffect para recursos que precisam de limpeza. Preste atencao na ordem dos Modifiers: cada modifier e aplicado em sequência e afeta o resultado visual de forma cumulativa. Por exemplo, padding antes de background adiciona espaco dentro da area colorida, enquanto a ordem inversa adiciona espaco fora. Perguntas Frequentes P: Qual a diferenca entre remember e rememberSaveable no Compose? R: remember preserva o estado entre recomposicoes, mas o valor se perde em mudancas de configuração (como rotação de tela) ou quando o processo e destruído. rememberSaveable salva o estado automaticamente no SavedStateHandle, sobrevivendo a mudancas de configuração e até a morte do processo, desde que o valor seja serializavel.\nP: Composables podem ser usados fora do Android? R: Sim. Com o Compose Multiplatform da JetBrains, você pode usar Composables em aplicações desktop (JVM), web (via Kotlin/Wasm) e iOS. A API de composicao e recomposicao e a mesma; o que muda sao os componentes de plataforma subjacentes que renderizam os elementos visuais.\nP: Como testar Composables de forma automatizada? R: Use a biblioteca compose-ui-test que fornece a ComposeTestRule. Com ela você pode renderizar Composables isolados, interagir com elementos via onNodeWithText e performClick, e verificar estados com assertivas como assertIsDisplayed. Testes de Composable executam no JVM sem precisar de um emulador.\nP: Por que meu Composable esta recompondo mais vezes do que o esperado? R: Recomposicoes excessivas geralmente acontecem quando o estado e lido em um escopo mais amplo do que necessário, quando lambdas sao recriadas a cada recomposicao (use remember para estabiliza-las), ou quando objetos de dados não implementam equals corretamente. Use o Layout Inspector do Android Studio para identificar quais Composables estao recompondo e com que frequência.\nErros comuns Colocar lógica de negócio dentro do Composable: Composables devem apenas descrever UI. Logica de negócio pertence ao ViewModel ou a camadas inferiores.\nEsquecer remember: sem remember, o estado e recriado a cada recomposicao, perdendo o valor anterior.\n// Errado: contagem volta a 0 a cada recomposicao @Composable fun ContadorQuebrado() { var contagem = mutableStateOf(0) // Falta remember! // ... } Efeitos colaterais descontrolados: fazer chamadas de rede, acessar banco de dados ou modificar estado global diretamente dentro de um Composable sem usar LaunchedEffect ou similar.\nNao elevar o estado (state hoisting): manter estado em componentes filhos quando ele deveria ser controlado pelo pai. Isso dificulta reutilização e testes.\nIgnorar a ordem dos Modifiers: como modifiers são aplicados em cadeia, a ordem afeta o resultado visual. Testar e visualizar com @Preview ajuda a pegar esses problemas cedo.\nState hoisting Um padrão fundamental em Compose e elevar o estado para o componente pai:\n// Componente stateless (sem estado proprio) @Composable fun CampoDeTexto( valor: String, onValorMudou: (String) -\u0026gt; Unit ) { TextField( value = valor, onValueChange = onValorMudou ) } // Componente pai controla o estado @Composable fun Formulario() { var nome by remember { mutableStateOf(\u0026#34;\u0026#34;) } CampoDeTexto( valor = nome, onValorMudou = { nome = it } ) } Isso torna CampoDeTexto reutilizavel e testavel, pois ele não gerencia seu próprio estado.\nTermos relacionados State: o mecanismo de estado reativo que aciona recomposicoes quando valores mudam. Modifier: objeto que configura aparencia e comportamento de componentes Compose. ViewModel: gerencia estado e lógica de negócio fora da camada de UI. LaunchedEffect: API para executar efeitos colaterais controlados dentro de Composables. Recomposicao: processo de reexecucao de funções Composable quando seus inputs mudam. remember: função que preserva estado entre recomposicoes. Composables representam uma mudanca de paradigma na construcao de interfaces em Kotlin. Ao tratar a UI como função do estado, o Compose elimina toda uma classe de bugs relacionados a sincronizacao entre dados e interface, tornando o desenvolvimento mais previsivel e produtivo.\n","permalink":"https://kotlin.dev.br/glossario/composable/","summary":"\u003ch2 id=\"o-que-é-composable-em-kotlin\"\u003eO que é Composable em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUma função \u003cstrong\u003eComposable\u003c/strong\u003e é uma função anotada com \u003ccode\u003e@Composable\u003c/code\u003e que descreve parte da interface do usuário no \u003cstrong\u003eJetpack Compose\u003c/strong\u003e, o toolkit moderno de UI declarativa do Android. Em vez de montar telas com XML e manipular Views programaticamente, você escreve funções Kotlin que descrevem como a UI deve parecer para um dado estado.\u003c/p\u003e\n\u003cp\u003eO Compose e inspirado em frameworks como React e Flutter, mas aproveita todo o poder do Kotlin: type safety, extension functions, coroutines é uma sintaxe concisa que faz a construcao de interfaces parecer natural.\u003c/p\u003e","title":"Composable em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"Trabalhar como freelancer Kotlin no Brasil é uma opção cada vez mais viável e lucrativa. Com a demanda crescente por desenvolvedores Kotlin é a expansao do trabalho remoto, profissionais qualificados podem construir uma carreira independente com excelente remuneracao. Neste guia, vou cobrir tudo que você precisa saber para começar.\nO Cenario do Freelancing em Kotlin O mercado de freelancing para desenvolvedores Kotlin no Brasil esta em um momento favoravel. Varios fatores contribuem para isso:\nEscassez de profissionais: A demanda por Kotlin supera a oferta, o que valoriza freelancers Trabalho remoto consolidado: Empresas se acostumaram com times distribuidos Dolar favoravel: Projetos internacionais pagam em moeda forte Diversidade de projetos: Android, backend, KMP criam múltiplas fontes de trabalho Tipos de Trabalho Freelance com Kotlin Desenvolvimento Android A maior fatia de projetos freelance Kotlin e para desenvolvimento Android:\n// Tipo de projeto comum: MVP de app para startup // Demonstra competencia técnica e organizacao @HiltViewModel class HomeViewModel @Inject constructor( private val getPopularProducts: GetPopularProductsUseCase, private val searchProducts: SearchProductsUseCase, private val analytics: AnalyticsTracker ) : ViewModel() { private val _uiState = MutableStateFlow(HomeUiState()) val uiState: StateFlow\u0026lt;HomeUiState\u0026gt; = _uiState.asStateFlow() private val searchQuery = MutableStateFlow(\u0026#34;\u0026#34;) init { carregarProdutosPopulares() observarBusca() } private fun carregarProdutosPopulares() { viewModelScope.launch { getPopularProducts() .onSuccess { produtos -\u0026gt; _uiState.update { it.copy( populares = produtos, loading = false )} } .onFailure { erro -\u0026gt; _uiState.update { it.copy( error = erro.message, loading = false )} } } } private fun observarBusca() { viewModelScope.launch { searchQuery .debounce(300) .filter { it.length \u0026gt;= 3 } .distinctUntilChanged() .flatMapLatest { query -\u0026gt; flow { emit(searchProducts(query)) } } .collect { result -\u0026gt; result.onSuccess { produtos -\u0026gt; _uiState.update { it.copy(resultadosBusca = produtos) } analytics.track(\u0026#34;search_completed\u0026#34;) } } } } fun onSearchQueryChanged(query: String) { searchQuery.value = query } } Desenvolvimento Backend Projetos backend são geralmente mais longos e melhor remunerados:\n// API para e-commerce - Projeto freelance tipico @Configuration class SecurityConfig { @Bean fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { return http .csrf { it.disable() } .authorizeHttpRequests { auth -\u0026gt; auth .requestMatchers(\u0026#34;/api/public/**\u0026#34;).permitAll() .requestMatchers(\u0026#34;/api/admin/**\u0026#34;).hasRole(\u0026#34;ADMIN\u0026#34;) .anyRequest().authenticated() } .oauth2ResourceServer { it.jwt {} } .build() } } @Service class OrderService( private val orderRepository: OrderRepository, private val paymentGateway: PaymentGateway, private val notificationService: NotificationService, private val inventoryService: InventoryService ) { @Transactional suspend fun processOrder(request: CreateOrderRequest): Order { // Validar estoque val items = request.items.map { item -\u0026gt; val available = inventoryService.checkAvailability( item.productId, item.quantity ) if (!available) { throw InsufficientStockException(item.productId) } item.toOrderItem() } // Criar pedido val order = Order( id = OrderId.generate(), customerId = request.customerId, items = items, total = items.sumOf { it.subtotal }, status = OrderStatus.PENDING ) val saved = orderRepository.save(order) // Processar pagamento val payment = paymentGateway.charge( amount = order.total, customerId = order.customerId, orderId = order.id ) // Atualizar status e notificar val updated = saved.copy( status = if (payment.approved) OrderStatus.PAID else OrderStatus.PAYMENT_FAILED, paymentId = payment.id ) orderRepository.save(updated) if (payment.approved) { inventoryService.reserve(items) notificationService.sendOrderConfirmation(updated) } return updated } } Consultoria e Migração Ajudar empresas a migrar de Java para Kotlin e um nicho lucrativo:\n// Serviço de consultoria: migrar codigo Java legado para Kotlin idiomatico // ANTES (Java convertido literalmente) class UserService(private val repository: UserRepository) { fun getUser(id: String): User? { val user = repository.findById(id) if (user != null) { if (user.isActive()) { return user } else { return null } } return null } } // DEPOIS (Kotlin idiomatico) class UserService(private val repository: UserRepository) { fun getUser(id: String): User? { return repository.findById(id)?.takeIf { it.isActive } } } Precificacao A precificacao e uma das partes mais dificeis do freelancing. Aqui estao referências para o mercado brasileiro:\nProjetos Nacionais (BRL) Junior: R$ 50-80/hora Pleno: R$ 100-180/hora Senior: R$ 200-350/hora Projeto completo (app simples): R$ 15.000-40.000 Projeto completo (app complexo): R$ 50.000-150.000+ Projetos Internacionais (USD) Pleno: $30-50/hora Senior: $50-100/hora Especialista KMP: $80-150/hora A dica e não cobrar por hora em projetos com escopo definido. Estime o tempo, adicione uma margem de 30-50% para imprevistos e apresente um valor fixo por entrega.\nOnde Encontrar Projetos Plataformas Globais Toptal: A mais seletiva, mas com projetos de alta qualidade e remuneracao Upwork: Grande volume de projetos, boa para começar Arc.dev: Foco em desenvolvedores, projetos de qualidade Turing: Matching com empresas americanas Plataformas e Canais Brasileiros LinkedIn: Otimize seu perfil para \u0026ldquo;Kotlin Freelancer\u0026rdquo; Grupos Telegram: Comunidades de desenvolvimento frequentemente postam projetos Indicacoes: A melhor fonte de projetos vem de networking Networking Direto Contribua em projetos open source Escreva artigos tecnicos sobre Kotlin Participe de eventos e meetups da comunidade Mantenha um portfolio online atualizado Aspectos Legais e Financeiros Formalizacao Para trabalhar como freelancer no Brasil, você tem opções:\nMEI (Microempreendedor Individual): Para faturamento até R$ 81.000/ano. Simples e barato, mas tem limitações ME (Simples Nacional): Para faturamento maior, com aliquotas progressivas PJ (Lucro Presumido): Para quem fatura acima de R$ 500.000/ano ou quer otimizar impostos Para projetos internacionais, você precisa de:\nCNPJ ativo Conta bancaria PJ Conhecimento sobre recebimento de pagamentos internacionais (Wise, Payoneer, transferencia bancaria) Contratos Sempre trabalhe com contrato, mesmo para projetos pequenos. O contrato deve cobrir:\nEscopo detalhado do trabalho Cronograma e marcos de entrega Valores e condições de pagamento Propriedade intelectual Clausulas de cancelamento Confidencialidade (NDA quando necessário) Gerenciamento de Projetos Como freelancer, você e responsavel por tudo: código, comunicação, prazos e qualidade.\nComunicação com o Cliente Envie updates semanais mesmo que o cliente não peça Use screenshots e videos para mostrar progresso Documente decisoes tecnicas por escrito Seja transparente sobre problemas e atrasos Estimativas Realistas A regra de ouro: estime quanto tempo você acha que vai levar, depois multiplique por 1.5. Imprevistos sempre acontecem:\nMudancas de requisito Bugs inesperados Integração com APIs de terceiros Reviews e ajustes Construindo Reputacao O sucesso como freelancer depende de reputacao. Algumas estrategias:\nEntregue sempre no prazo ou antes: Nada constroi reputacao como confiabilidade Supere expectativas: Adicione pequenas melhorias que o cliente não pediu Peca avaliacoes: Apos cada projeto bem sucedido, peça um depoimento Mantenha relacionamentos: Clientes satisfeitos voltam e indicam Conclusão Freelancing com Kotlin e uma carreira viável e potencialmente muito lucrativa no Brasil. A combinacao de alta demanda, escassez de profissionais e oportunidades internacionais cria um cenário favoravel para quem esta disposto a investir na construcao de uma carreira independente.\nComece com projetos menores para ganhar experiência e reputacao, formalize-se legalmente, invista em networking e nunca pare de evoluir tecnicamente. O mercado para Kotlin só cresce, e freelancers qualificados estao em posicao privilegiada para aproveitar essa onda. Diversificar seu stack com Go ou Python pode abrir ainda mais projetos freelance no seu radar.\n","permalink":"https://kotlin.dev.br/blog/freelancer-kotlin-brasil/","summary":"\u003cp\u003eTrabalhar como freelancer Kotlin no Brasil é uma opção cada vez mais viável e lucrativa. Com a demanda crescente por desenvolvedores Kotlin é a expansao do trabalho remoto, profissionais qualificados podem construir uma carreira independente com excelente remuneracao. Neste guia, vou cobrir tudo que você precisa saber para começar.\u003c/p\u003e\n\u003ch2 id=\"o-cenario-do-freelancing-em-kotlin\"\u003eO Cenario do Freelancing em Kotlin\u003c/h2\u003e\n\u003cp\u003eO mercado de freelancing para desenvolvedores Kotlin no Brasil esta em um momento favoravel. Varios fatores contribuem para isso:\u003c/p\u003e","title":"Freelancer Kotlin no Brasil: Como Comecar e Prosperar | Kotlin Brasil"},{"content":"O que é Callback em Kotlin? Um callback é uma função passada como argumento para outra função, que sera executada em um momento posterior \u0026ndash; geralmente quando uma operação assíncrona termina ou quando um evento específico ocorre. Em Kotlin, callbacks são implementados de forma elegante usando lambdas, funções de ordem superior e interfaces funcionais.\nO conceito e antigo e existe em praticamente todas as linguagens, mas em Kotlin ele ganha uma sintaxe limpa e concisa que torna o código muito mais legivel do que em linguagens como Java.\nCallback básico com lambda A forma mais simples de callback em Kotlin e passar uma lambda como parametro:\nfun buscarDados(onSucesso: (String) -\u0026gt; Unit, onErro: (Exception) -\u0026gt; Unit) { try { // Simula busca de dados val resultado = \u0026#34;Dados carregados\u0026#34; onSucesso(resultado) } catch (e: Exception) { onErro(e) } } fun main() { buscarDados( onSucesso = { dados -\u0026gt; println(\u0026#34;Sucesso: $dados\u0026#34;) }, onErro = { erro -\u0026gt; println(\u0026#34;Erro: ${erro.message}\u0026#34;) } ) } Aqui, onSucesso e onErro são callbacks. A função buscarDados recebe as duas lambdas e chama a apropriada dependendo do resultado da operação.\nCallback com interface funcional Em cenários de interoperabilidade com Java ou quando você quer um contrato mais explicito, você pode usar interfaces funcionais:\nfun interface OnResultadoListener { fun onResultado(dados: String) } class Repositorio { fun carregar(listener: OnResultadoListener) { // Simula processamento val resultado = \u0026#34;Dados do servidor\u0026#34; listener.onResultado(resultado) } } fun main() { val repo = Repositorio() // Usando SAM conversion repo.carregar { dados -\u0026gt; println(\u0026#34;Recebido: $dados\u0026#34;) } // Ou de forma explicita repo.carregar(object : OnResultadoListener { override fun onResultado(dados: String) { println(\u0026#34;Recebido: $dados\u0026#34;) } }) } A palavra-chave fun interface permite que o Kotlin converta automaticamente uma lambda em uma implementação da interface (SAM conversion), mantendo o código conciso.\nCallback para eventos de UI Um uso clássico de callbacks e em componentes de interface grafica, como botoes:\nclass Botao { private var onClickListener: (() -\u0026gt; Unit)? = null fun setOnClickListener(listener: () -\u0026gt; Unit) { onClickListener = listener } fun clicar() { onClickListener?.invoke() } } fun main() { val botao = Botao() botao.setOnClickListener { println(\u0026#34;Botao foi clicado!\u0026#34;) } botao.clicar() // Botao foi clicado! } Esse padrão e fundamental no desenvolvimento Android, onde callbacks conectam acoes do usuário a lógica de negócio.\nCallback hell e como evitar O problema clássico com callbacks e o callback hell \u0026ndash; aninhamento excessivo que torna o código ilegivel:\n// Callback hell -- evite isso fun carregarTudo() { buscarUsuario { usuario -\u0026gt; buscarPedidos(usuario.id) { pedidos -\u0026gt; buscarDetalhes(pedidos.first().id) { detalhes -\u0026gt; buscarEndereco(detalhes.enderecoId) { endereco -\u0026gt; println(\u0026#34;Endereco: $endereco\u0026#34;) } } } } } Em Kotlin, a solução moderna para esse problema são as coroutines, que permitem escrever código assíncrono de forma sequencial:\n// Com coroutines -- muito mais limpo suspend fun carregarTudo() { val usuario = buscarUsuario() val pedidos = buscarPedidos(usuario.id) val detalhes = buscarDetalhes(pedidos.first().id) val endereco = buscarEndereco(detalhes.enderecoId) println(\u0026#34;Endereco: $endereco\u0026#34;) } Convertendo callbacks para coroutines Quando você trabalha com APIs baseadas em callbacks (especialmente bibliotecas Java), pode converte-las para suspending functions usando suspendCoroutine ou suspendCancellableCoroutine:\nimport kotlinx.coroutines.* import kotlin.coroutines.* // API legada baseada em callback fun buscarDadosLegado(callback: (Result\u0026lt;String\u0026gt;) -\u0026gt; Unit) { // Simula operacao assíncrona callback(Result.success(\u0026#34;Dados legados\u0026#34;)) } // Wrapper com coroutines suspend fun buscarDadosSuspend(): String = suspendCancellableCoroutine { continuation -\u0026gt; buscarDadosLegado { resultado -\u0026gt; resultado .onSuccess { continuation.resume(it) } .onFailure { continuation.resumeWithException(it) } } } fun main() = runBlocking { val dados = buscarDadosSuspend() println(dados) } Essa técnica e extremamente útil ao migrar código legado para coroutines de forma incremental.\nCallback com tipo generico Você pode criar callbacks reutilizaveis usando generics:\ntypealias Callback\u0026lt;T\u0026gt; = (Result\u0026lt;T\u0026gt;) -\u0026gt; Unit fun \u0026lt;T\u0026gt; executarAsync(operacao: () -\u0026gt; T, callback: Callback\u0026lt;T\u0026gt;) { try { val resultado = operacao() callback(Result.success(resultado)) } catch (e: Exception) { callback(Result.failure(e)) } } fun main() { executarAsync( operacao = { 42 * 2 }, callback = { resultado -\u0026gt; resultado .onSuccess { println(\u0026#34;Resultado: $it\u0026#34;) } .onFailure { println(\u0026#34;Erro: ${it.message}\u0026#34;) } } ) } O typealias torna a assinatura mais legivel, e o uso de Result padroniza o tratamento de sucesso e erro.\nQuando usar callbacks Callbacks ainda são úteis em vários cenários:\nInteroperabilidade com Java: muitas bibliotecas Java usam o padrão listener/callback, e você precisa se adaptar. Eventos de UI: cliques, gestos e outros eventos de interface são naturalmente modelados como callbacks. APIs simples: quando a operação e direta e não há aninhamento, um callback e perfeitamente adequado. Bibliotecas e frameworks: se você esta criando uma biblioteca que precisa ser usada por projetos que não usam coroutines. Porem, para lógica assíncrona complexa com múltiplas etapas, prefira coroutines. Elas eliminam o aninhamento é fácilitam o tratamento de erros com try-catch normal.\nCasos de Uso no Mundo Real Listeners de eventos em Android: toda interação do usuário com a interface \u0026ndash; cliques em botoes, mudancas em campos de texto, gestos de swipe \u0026ndash; e modelada como callback. O setOnClickListener do Android e o exemplo mais clássico, onde uma lambda e registrada para ser executada quando o usuário interage com o componente.\nRespostas de APIs de rede: bibliotecas como Retrofit e OkHttp usam callbacks para notificar quando uma requisicao HTTP foi concluida. O callback recebe a resposta do servidor ou um objeto de erro, permitindo que o código que fez a requisicao processe o resultado sem bloquear a thread principal.\nObservadores de ciclo de vida: no Android, callbacks como onStart(), onResume(), onPause() e onDestroy() notificam o componente sobre mudancas no ciclo de vida. Frameworks como o Lifecycle do AndroidX usam esse padrão para que bibliotecas reajam automaticamente a mudancas de estado da Activity ou Fragment.\nProcessamento de arquivos e streams: operações de leitura/escrita em arquivos grandes frequentemente usam callbacks para reportar progresso. Em vez de bloquear a thread até a operação terminar, o sistema notifica o chamador a cada bloco processado, permitindo exibir barras de progresso ou cancelar a operação.\nBoas Praticas Prefira lambdas com parametros nomeados na assinatura da função (onSucesso, onErro) em vez de um único callback generico. Nomes explicitos tornam a intencao clara e facilitam a leitura do código no ponto de chamada. Garanta que o callback seja chamado em exatamente um caminho de execução. Esquecer de chamar o callback em algum branch condicional causa bugs silenciosos, e chama-lo mais de uma vez pode causar comportamento inesperado. Ao trabalhar com callbacks em Android, sempre considere o ciclo de vida do componente. Cancele ou remova callbacks quando a Activity ou Fragment for destruído para evitar memory leaks e crashes por referência a contextos invalidos. Para APIs novas, prefira coroutines e suspend fun em vez de callbacks. Use suspendCancellableCoroutine para adaptar APIs legadas baseadas em callback para o mundo das coroutines, facilitando composicao e tratamento de erros. Utilize typealias para dar nomes significativos a tipos de callback complexos, como typealias OnResultado\u0026lt;T\u0026gt; = (Result\u0026lt;T\u0026gt;) -\u0026gt; Unit. Isso melhora a legibilidade das assinaturas de funções sem adicionar overhead. Perguntas Frequentes P: Quando devo usar callbacks em vez de coroutines em Kotlin? R: Use callbacks quando estiver trabalhando com interoperabilidade Java (bibliotecas que já usam o padrão listener), eventos de UI simples (cliques, gestos) ou quando estiver criando bibliotecas que precisam ser acessiveis a projetos que não usam coroutines. Para lógica assíncrona com múltiplas etapas, prefira coroutines.\nP: Como evitar memory leaks com callbacks em Android? R: Registre callbacks em onStart() ou onResume() e remova-os em onStop() ou onPause(). Evite usar lambdas que capturam referência a Activities ou Views. Se necessário, use WeakReference ou migre para LiveData/Flow que respeitam o ciclo de vida automaticamente.\nP: Qual a diferenca entre um callback e um listener em Kotlin? R: Na prática, sao o mesmo conceito. \u0026ldquo;Listener\u0026rdquo; e o termo mais comum no ecossistema Android e Java, geralmente implementado como uma interface com um ou mais métodos. \u0026ldquo;Callback\u0026rdquo; e o termo generico da programacao para qualquer função passada como argumento para ser chamada posteriormente. Em Kotlin, ambos podem ser implementados como lambdas.\nP: E possível converter qualquer API baseada em callback para coroutines? R: Sim, usando suspendCancellableCoroutine. Voce encapsula a chamada da API legada dentro dessa função, e no callback de sucesso chama continuation.resume(valor), e no callback de erro chama continuation.resumeWithException(exceção). Isso transforma a API em uma suspend fun que pode ser chamada de forma sequencial.\nErros comuns Callback hell: aninhar callbacks excessivamente. Use coroutines ou quebre a lógica em funções menores.\nEsquecer de chamar o callback: se a função tem caminhos de execução diferentes (sucesso, erro, timeout), certifique-se de que o callback e chamado em todos eles.\nChamar o callback mais de uma vez: a maioria dos contratos espera que o callback seja chamado exatamente uma vez. Chamar múltiplas vezes pode causar comportamento inesperado.\nNao tratar erros: passar apenas um callback de sucesso e ignorar falhas. Sempre forneca um mecanismo para tratar erros.\nReter referências de callback: em Android, manter uma referência a um callback que contém uma referência a uma Activity pode causar memory leaks. Use WeakReference ou cancele o callback quando o componente for destruído.\nTermos relacionados Lambda: a forma mais comum de expressar callbacks em Kotlin, usando a sintaxe { parametros -\u0026gt; corpo }. Higher-Order Function: funções que recebem ou retornam outras funções, o mecanismo que permite callbacks em Kotlin. Coroutine: alternativa moderna aos callbacks para programação assíncrona, eliminando o callback hell. suspend: modificador que transforma uma função em uma função suspensa, substituindo callbacks por retorno direto. Flow: stream reativo que substitui callbacks repetitivos por um fluxo de dados continuo. SAM Conversion: mecanismo que converte lambdas em implementacoes de interfaces funcionais Java. Callbacks são um dos padrões mais fundamentais da programação. Em Kotlin, a combinacao de lambdas, funções de ordem superior e interfaces funcionais torna sua implementação elegante e expressiva, enquanto coroutines oferecem uma evolução natural para cenários mais complexos.\n","permalink":"https://kotlin.dev.br/glossario/callback/","summary":"\u003ch2 id=\"o-que-é-callback-em-kotlin\"\u003eO que é Callback em Kotlin?\u003c/h2\u003e\n\u003cp\u003eUm \u003cstrong\u003ecallback\u003c/strong\u003e é uma função passada como argumento para outra função, que sera executada em um momento posterior \u0026ndash; geralmente quando uma operação assíncrona termina ou quando um evento específico ocorre. Em Kotlin, callbacks são implementados de forma elegante usando \u003cstrong\u003elambdas\u003c/strong\u003e, \u003cstrong\u003efunções de ordem superior\u003c/strong\u003e e \u003cstrong\u003einterfaces funcionais\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eO conceito e antigo e existe em praticamente todas as linguagens, mas em Kotlin ele ganha uma sintaxe limpa e concisa que torna o código muito mais legivel do que em linguagens como Java.\u003c/p\u003e","title":"Callback em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Boxing em Kotlin? Boxing é o processo de encapsular um tipo primitivo (como Int, Long, Double) dentro de um objeto wrapper correspondente (como java.lang.Integer, java.lang.Long, java.lang.Double). O processo inverso, extrair o valor primitivo do objeto, é chamado de unboxing.\nEm Kotlin, diferente do Java, você não declara explicitamente int vs Integer. Tudo e Int. Porem, o compilador decide por baixo dos panos se vai usar o tipo primitivo (int) ou o wrapper (Integer) dependendo do contexto. Entender quando o boxing acontece e fundamental para escrever código performatico.\nComo o compilador decide? O Kotlin compila tipos como Int para primitivos JVM (int) sempre que possível. Porem, em certas situacoes, o boxing é obrigatório:\nQuando o tipo e nullable (Int?), o valor precisa ser boxed porque primitivos não podem ser null. Quando o tipo é usado como argumento generico (List\u0026lt;Int\u0026gt;), pois generics na JVM trabalham com objetos. Quando o tipo é usado em contextos que exigem referência de objeto. val a: Int = 42 // Compilado como primitivo int val b: Int? = 42 // Compilado como Integer (boxed) val lista: List\u0026lt;Int\u0026gt; = listOf(1, 2, 3) // Cada Int e boxed como Integer Impacto na performance O boxing tem custo. Cada vez que um primitivo e boxed, um novo objeto e alocado no heap. Em loops intensivos ou coleções grandes, isso pode gerar pressao significativa no garbage collector.\n// Versão com boxing: cada iteracao cria um objeto Integer fun somaBoxed(lista: List\u0026lt;Int\u0026gt;): Int { var soma = 0 for (valor in lista) { soma += valor // unboxing acontece aqui } return soma } // Versão sem boxing: usa IntArray com primitivos fun somaPrimitiva(array: IntArray): Int { var soma = 0 for (valor in array) { soma += valor // nenhum boxing } return soma } A segunda versão e significativamente mais rápida para arrays grandes porque não envolve alocacao de objetos nem garbage collection adicional.\nArrays especializados Para evitar boxing em arrays, Kotlin oferece tipos especializados:\nval intArray: IntArray = intArrayOf(1, 2, 3) // int[] na JVM val longArray: LongArray = longArrayOf(1L, 2L, 3L) // long[] na JVM val doubleArray: DoubleArray = doubleArrayOf(1.0, 2.0) // double[] na JVM // Comparando com Array\u0026lt;Int\u0026gt; que sofre boxing val boxedArray: Array\u0026lt;Int\u0026gt; = arrayOf(1, 2, 3) // Integer[] na JVM Sempre prefira IntArray, LongArray, DoubleArray e similares quando performance for importante.\nIdentidade vs igualdade com boxing Um detalhe sutil e que o boxing pode afetar a identidade de objetos:\nval a: Int = 127 val boxedA: Int? = a val outroBoxedA: Int? = a println(boxedA === outroBoxedA) // true (cache de -128 a 127) val b: Int = 128 val boxedB: Int? = b val outroBoxedB: Int? = b println(boxedB === outroBoxedB) // false (fora do cache) println(boxedB == outroBoxedB) // true (igualdade estrutural) A JVM faz cache de Integer para valores entre -128 e 127. Fora dessa faixa, cada boxing cria um novo objeto, entao a comparação de identidade (===) retorna false. Sempre use == para comparar valores numericos.\nBoxing em funções genericas Funções genericas sempre causam boxing porque a JVM não suporta generics com primitivos:\nfun \u0026lt;T\u0026gt; imprimir(valor: T) { println(valor) } fun main() { imprimir(42) // 42 e boxed para Integer antes de ser passado } Para evitar isso em casos específicos, você pode usar funções inline com reified:\ninline fun \u0026lt;reified T\u0026gt; verificarTipo(valor: T): String { return when (T::class) { Int::class -\u0026gt; \u0026#34;Inteiro\u0026#34; String::class -\u0026gt; \u0026#34;String\u0026#34; else -\u0026gt; \u0026#34;Outro\u0026#34; } } Porem, isso não elimina completamente o boxing em todos os cenários. Para performance crítica, considere sobrecarregar a função com versões específicas para cada tipo primitivo.\nQuando usar tipos que causam boxing O boxing não e algo que você precisa evitar obsessivamente. Na maioria dos casos, o impacto e negligenciavel. Preocupe-se com boxing apenas quando:\nVocê esta processando milhoes de elementos em loops apertados. Você esta trabalhando com coleções muito grandes onde a alocacao de memória importa. Profiling mostrou que garbage collection esta sendo um gargalo no seu sistema. Você esta desenvolvendo bibliotecas de alta performance ou algoritmos numericos. Para código de aplicação comum, como chamadas de API, manipulação de UI ou lógica de negocios, o boxing e perfeitamente aceitavel e não merece otimização prematura.\nCasos de Uso no Mundo Real Processamento de dados em larga escala: em pipelines de ETL e processamento batch que manipulam milhoes de registros numericos, evitar boxing ao usar IntArray e DoubleArray em vez de List\u0026lt;Int\u0026gt; e List\u0026lt;Double\u0026gt; pode reduzir o consumo de memória pela metade e acelerar o processamento significativamente, além de diminuir a pressao no garbage collector.\nMotores de jogos e simulacoes: em game loops que executam calculos de fisica, colisao e renderizacao dezenas de vezes por segundo, operações com tipos primitivos sem boxing sao essenciais. Cada frame pode envolver milhares de calculos com coordenadas e vetores, e a alocacao de objetos wrapper nesse contexto causa stuttering perceptivel ao usuário.\naplicações Android com listas grandes: ao exibir listas com milhares de itens em RecyclerView ou LazyColumn, coleções de IDs ou indices como IntArray em vez de List\u0026lt;Int\u0026gt; reduzem a alocacao de memória e diminuem o risco de janks na interface, especialmente em dispositivos com hardware mais limitado.\nBibliotecas de machine learning e estatistica: bibliotecas que realizam operações matriciais, calculos estatisticos ou treinamento de modelos precisam operar sobre arrays densos de primitivos. O boxing nessas situacoes não e apenas uma questao de performance, mas também de viabilidade, já que a diferenca de consumo de memória pode tornar o processamento impraticavel.\nBoas Praticas Use IntArray, LongArray, DoubleArray e demais arrays especializados em vez de Array\u0026lt;Int\u0026gt;, Array\u0026lt;Long\u0026gt; ou Array\u0026lt;Double\u0026gt; sempre que estiver trabalhando com colecoes numericas onde performance importa. Evite declarar variaveis como nullable (Int?, Double?) quando o valor nunca sera null. Tipos nullable forcam boxing na JVM, gerando alocacao desnecessaria de objetos. Sempre compare valores numericos com == (igualdade estrutural) e nunca com === (identidade referencial). O boxing pode criar objetos diferentes para o mesmo valor numerico, fazendo === retornar false de forma inesperada. Ao criar funções utilitarias que operam sobre tipos numericos e precisam de alta performance, considere fornecer sobrecargas especificas para cada tipo primitivo em vez de depender exclusivamente de generics, que sempre causam boxing. Utilize ferramentas de profiling como o Android Profiler ou o JMH (Java Microbenchmark Harness) para medir o impacto real do boxing antes de otimizar. otimização prematura reduz legibilidade sem beneficio mensuravel. Perguntas Frequentes P: Como saber se o meu código esta sofrendo boxing desnecessário? R: Voce pode inspecionar o bytecode gerado pelo Kotlin usando a opção \u0026ldquo;Show Kotlin Bytecode\u0026rdquo; no IntelliJ IDEA e clicar em \u0026ldquo;Decompile\u0026rdquo;. Procure por chamadas a Integer.valueOf(), Long.valueOf() e similares, que indicam boxing. Alem disso, ferramentas de profiling como o JMH e o Android Profiler ajudam a medir o impacto real em tempo de execução.\nP: Value classes (@JvmInline value class) eliminam o boxing? R: Em muitos cenários sim. Uma value class que encapsula um tipo primitivo e representada como o primitivo em tempo de execução, sem alocacao de objeto adicional. Porem, o boxing ainda acontece quando a value class e usada como tipo nullable, em colecoes genericas ou em contextos que exigem referência de objeto, seguindo as mesmas regras de qualquer tipo primitivo.\nP: Existe diferenca de performance entre listOf(1, 2, 3) e intArrayOf(1, 2, 3)? R: Sim. listOf(1, 2, 3) cria uma List\u0026lt;Int\u0026gt; onde cada elemento e boxed como java.lang.Integer, resultando em tres alocacoes de objetos além da própria lista. intArrayOf(1, 2, 3) cria um int[] nativo da JVM sem nenhum boxing. Para listas pequenas a diferenca e negligenciavel, mas em colecoes com milhares de elementos o impacto na memória e no garbage collector se torna relevante.\nP: Kotlin Multiplatform lida com boxing da mesma forma que a JVM? R: Nao. O boxing e um conceito específico da JVM, onde generics só trabalham com objetos. Em plataformas nativas (Kotlin/Native), não existe essa distincao entre primitivos e objetos wrapper. Em Kotlin/JS, os números sao mapeados para o tipo number do JavaScript. Portanto, preocupacoes com boxing sao mais relevantes ao direcionar a JVM ou o Android.\nErros comuns Comparar tipos nullable com ===: como vimos, boxing pode criar objetos diferentes para o mesmo valor. Sempre use == para comparações de valor.\nIgnorar arrays especializados: usar Array\u0026lt;Int\u0026gt; em vez de IntArray quando performance importa. A diferenca pode ser significativa em coleções grandes.\nOtimizar prematuramente: evitar List\u0026lt;Int\u0026gt; em favor de IntArray em todo lugar, mesmo quando a lista e pequena e a legibilidade do código e mais importante.\nEsquecer que nullable causa boxing: declarar var contador: Int? = 0 quando o valor nunca sera null. Use Int sem interrogacao sempre que possível.\nNao considerar o boxing em benchmarks: ao comparar performance de diferentes abordagens, o boxing pode distorcer resultados se não for levado em conta.\nColeções sem boxing Para cenários de alta performance, existem bibliotecas que oferecem coleções especializadas sem boxing, como a biblioteca eclipse-collections ou implementacoes customizadas com IntArray como backing store:\nclass ListaDeInteiros { private var dados = IntArray(16) private var tamanho = 0 fun adicionar(valor: Int) { if (tamanho == dados.size) { dados = dados.copyOf(dados.size * 2) } dados[tamanho++] = valor } fun obter(indice: Int): Int = dados[indice] fun tamanho(): Int = tamanho } Termos relacionados Value Class: permite criar tipos que encapsulam um primitivo sem overhead de boxing adicional em tempo de execução. Inline: funções inline podem ajudar a reduzir boxing em certos contextos com lambdas. Reified: permite acessar o tipo generico em tempo de execução em funções inline, evitando algumas formas de boxing. Nullable: tipos nullable (Int?) sempre causam boxing porque primitivos não podem ser null na JVM. IntArray/LongArray/DoubleArray: arrays especializados que evitam boxing, armazenando primitivos diretamente. Compreender boxing e unboxing e essencial para escrever Kotlin que seja ao mesmo tempo idiomatico e eficiente. Na maioria dos casos, confie no compilador. Nos casos onde performance e crítica, use as ferramentas que o Kotlin oferece para manter tudo no mundo dos primitivos.\n","permalink":"https://kotlin.dev.br/glossario/boxing/","summary":"\u003ch2 id=\"o-que-é-boxing-em-kotlin\"\u003eO que é Boxing em Kotlin?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eBoxing\u003c/strong\u003e é o processo de encapsular um tipo primitivo (como \u003ccode\u003eInt\u003c/code\u003e, \u003ccode\u003eLong\u003c/code\u003e, \u003ccode\u003eDouble\u003c/code\u003e) dentro de um objeto wrapper correspondente (como \u003ccode\u003ejava.lang.Integer\u003c/code\u003e, \u003ccode\u003ejava.lang.Long\u003c/code\u003e, \u003ccode\u003ejava.lang.Double\u003c/code\u003e). O processo inverso, extrair o valor primitivo do objeto, é chamado de \u003cstrong\u003eunboxing\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eEm Kotlin, diferente do Java, você não declara explicitamente \u003ccode\u003eint\u003c/code\u003e vs \u003ccode\u003eInteger\u003c/code\u003e. Tudo e \u003ccode\u003eInt\u003c/code\u003e. Porem, o compilador decide por baixo dos panos se vai usar o tipo primitivo (\u003ccode\u003eint\u003c/code\u003e) ou o wrapper (\u003ccode\u003eInteger\u003c/code\u003e) dependendo do contexto. Entender quando o boxing acontece e fundamental para escrever código performatico.\u003c/p\u003e","title":"Boxing em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"O que é Actor em Kotlin? O Actor é um padrão de concorrência onde uma entidade isolada (o ator) recebe mensagens através de um canal, processa uma de cada vez e mantém seu próprio estado interno de forma segura. Em Kotlin, esse padrão e implementado com coroutines e channels, aproveitando a infraestrutura do kotlinx.coroutines.\nA ideia central é simples: em vez de compartilhar estado entre várias threads e proteger com locks, você envia mensagens para um ator que é o único dono daquele estado. Como ele processa uma mensagem por vez, não há condições de corrida.\nPor que usar Actors? Quando múltiplas coroutines precisam acessar e modificar um mesmo recurso, o jeito clássico e usar Mutex ou synchronized. Funciona, mas pode ficar complexo e propenso a erros. O padrão Actor oferece uma alternativa elegante: encapsula o estado e a lógica de mutação em um único ponto, comunicando-se exclusivamente por mensagens.\nImagine um contador que várias partes do sistema precisam incrementar. Com o padrão Actor, todas enviam uma mensagem de \u0026ldquo;incrementar\u0026rdquo; e o ator faz a atualização de forma sequencial e segura.\nSintaxe e uso básico Em Kotlin, você pode implementar um actor usando uma coroutine que lê de um Channel. A biblioteca kotlinx.coroutines oferecia uma função actor (agora marcada como obsoleta na API experimental), mas o padrão continua válido e pode ser implementado manualmente.\nimport kotlinx.coroutines.* import kotlinx.coroutines.channels.* // Definindo os tipos de mensagem sealed class MensagemContador object Incrementar : MensagemContador() object Decrementar : MensagemContador() class ObterValor(val resposta: CompletableDeferred\u0026lt;Int\u0026gt;) : MensagemContador() fun CoroutineScope.contadorActor() = actor\u0026lt;MensagemContador\u0026gt; { var contador = 0 for (msg in channel) { when (msg) { is Incrementar -\u0026gt; contador++ is Decrementar -\u0026gt; contador-- is ObterValor -\u0026gt; msg.resposta.complete(contador) } } } Nesse exemplo, o ator e uma coroutine que fica em loop lendo mensagens do seu canal interno. Cada mensagem e processada sequencialmente, garantindo que o estado contador nunca sera acessado por duas coroutines ao mesmo tempo.\nExemplo completo com múltiplas coroutines import kotlinx.coroutines.* import kotlinx.coroutines.channels.* sealed class MensagemContador object Incrementar : MensagemContador() class ObterValor(val resposta: CompletableDeferred\u0026lt;Int\u0026gt;) : MensagemContador() fun CoroutineScope.contadorActor() = actor\u0026lt;MensagemContador\u0026gt; { var contador = 0 for (msg in channel) { when (msg) { is Incrementar -\u0026gt; contador++ is ObterValor -\u0026gt; msg.resposta.complete(contador) } } } fun main() = runBlocking { val ator = contadorActor() // Lancar 1000 coroutines que incrementam o contador val jobs = List(1000) { launch { repeat(100) { ator.send(Incrementar) } } } jobs.forEach { it.join() } // Obter o valor final val resposta = CompletableDeferred\u0026lt;Int\u0026gt;() ator.send(ObterValor(resposta)) println(\u0026#34;Contador final: ${resposta.await()}\u0026#34;) // 100000 ator.close() } Aqui, 1000 coroutines enviam 100 incrementos cada. O resultado sera sempre 100000, sem nenhuma condição de corrida, porque todas as operações passam pelo canal do ator e são processadas uma por uma.\nimplementação manual sem a função actor Como a função actor da biblioteca esta marcada como @ObsoleteCoroutinesApi, você pode implementar o mesmo padrão manualmente:\nimport kotlinx.coroutines.* import kotlinx.coroutines.channels.* class ContadorActor(scope: CoroutineScope) { private val canal = Channel\u0026lt;MensagemContador\u0026gt;(Channel.UNLIMITED) init { scope.launch { var contador = 0 for (msg in canal) { when (msg) { is Incrementar -\u0026gt; contador++ is Decrementar -\u0026gt; contador-- is ObterValor -\u0026gt; msg.resposta.complete(contador) } } } } suspend fun incrementar() = canal.send(Incrementar) suspend fun decrementar() = canal.send(Decrementar) suspend fun obterValor(): Int { val resposta = CompletableDeferred\u0026lt;Int\u0026gt;() canal.send(ObterValor(resposta)) return resposta.await() } fun fechar() = canal.close() } Essa versão encapsula o canal e expõe métodos com nomes claros, tornando o uso mais idiomatico e seguro.\nQuando usar Actors? O padrão Actor e ideal nos seguintes cenários:\nEstado mutavel compartilhado: quando várias coroutines precisam ler e escrever o mesmo recurso. Em vez de usar Mutex, você delega toda a mutação ao ator. Processamento sequencial de eventos: quando eventos chegam de fontes diferentes mas precisam ser tratados em ordem, como em filas de tarefas. Isolamento de estado: quando você quer garantir que apenas uma parte do código pode modificar determinado estado, facilitando testes e depuração. Sistemas reativos: em arquiteturas orientadas a eventos, actors funcionam como componentes independentes que se comunicam por mensagens. Nao use actors quando o estado não e compartilhado ou quando a lógica e simples o suficiente para um Mutex resolver sem complicacao.\nCasos de Uso no Mundo Real Gerenciamento de sessoes de usuário: em servidores web de alta concorrencia, cada sessao de usuário pode ser representada por um actor. Quando múltiplas requisicoes chegam para o mesmo usuário simultaneamente, o actor garante que atualizações no carrinho de compras, preferencias ou tokens de autenticação sejam processadas de forma sequencial, eliminando inconsistencias sem necessidade de locks explicitos.\nSistemas de chat e mensageria: aplicações de chat usam actors para representar salas ou conversas. Cada sala e um actor que recebe mensagens de múltiplos participantes, mantém o histórico em ordem e distribui as mensagens para os membros conectados. Isso simplifica enormemente a lógica de concorrencia em sistemas com milhares de salas ativas.\nControle de dispositivos IoT: em plataformas de Internet das Coisas, cada dispositivo fisico pode ser mapeado para um actor que mantém o estado atual do dispositivo (temperatura, status, configuração). Comandos enviados ao dispositivo passam pelo actor, que garante que não haja conflitos entre leituras de sensores e atualizações de configuração.\nRate limiting e throttling: actors funcionam naturalmente como controladores de taxa. Um actor que processa requisicoes a uma API externa pode manter um contador interno e aplicar limites de taxa sem precisar de estruturas concorrentes externas, já que todas as requisicoes passam por seu canal de mensagens.\nBoas Praticas Defina as mensagens do actor como uma sealed class ou sealed interface para garantir exaustividade no when e facilitar a manutenção quando novos tipos de mensagem forem adicionados. Sempre trate exceções dentro do loop do actor com try-catch por mensagem, não em torno do loop inteiro. Isso evita que uma mensagem mal-formada derrube o actor e perca todas as mensagens subsequentes. Prefira Channel.BUFFERED ou um tamanho fixo de buffer em vez de Channel.UNLIMITED. Buffers ilimitados podem esconder problemas de backpressure e consumir memória indefinidamente. Vincule o ciclo de vida do actor a um CoroutineScope adequado. Em Android, use viewModelScope; em servidores, use um scope vinculado ao ciclo de vida do servico. Nunca use GlobalScope para actors de longa duracao. Use CompletableDeferred para mensagens do tipo request-response, onde o emissor precisa de uma resposta. Isso permite comunicação bidirecional sem quebrar o encapsulamento do estado do actor. Perguntas Frequentes P: O padrão Actor ainda e relevante se a função actor do kotlinx.coroutines esta marcada como obsoleta? R: Sim. A função de conveniencia actor foi marcada como @ObsoleteCoroutinesApi, mas o padrão arquitetural continua perfeitamente válido e recomendado. A implementação manual usando um Channel e uma coroutine que lê desse canal oferece o mesmo resultado com mais controle sobre buffer, tratamento de erros e ciclo de vida.\nP: Qual a diferenca entre usar um Actor e um Mutex para proteger estado compartilhado? R: O Mutex protege uma seção crítica que qualquer coroutine pode acessar diretamente. O Actor encapsula o estado completamente, e ninguem o acessa diretamente \u0026ndash; tudo passa por mensagens. O Actor e mais seguro em sistemas complexos porque elimina a possibilidade de acessar o estado sem protecao, enquanto o Mutex depende da disciplina do desenvolvedor.\nP: Actors em Kotlin sao equivalentes aos Actors do Akka? R: Conceitualmente sim, ambos seguem o modelo de atores onde entidades isoladas se comunicam por mensagens. Porem, o Akka oferece um framework completo com supervisao hierárquica, clustering e persistencia de estado. Em Kotlin, actors sao mais leves e implementados como coroutines com channels, sem toda a infraestrutura que o Akka fornece.\nP: Como testar um actor de forma unitaria? R: Crie o actor dentro de um runBlocking ou runTest e envie mensagens diretamente pelo canal. Use CompletableDeferred para verificar respostas. Como o actor e determinístico (processa uma mensagem por vez), os testes sao previsiveis e não sofrem com problemas de timing.\nErros comuns Esquecer de fechar o ator: se você não chamar close() no canal, a coroutine do ator vai ficar suspensa indefinidamente esperando novas mensagens, causando vazamento de memória.\nUsar canal com buffer ilimitado sem controle: Channel.UNLIMITED pode consumir muita memória se as mensagens forem produzidas mais rápido do que consumidas. Considere usar Channel.BUFFERED ou um tamanho fixo.\nCapturar estado externo na coroutine do ator: o ator deve ser o único dono do seu estado. Se você compartilhar variaveis externas, perde toda a garantia de segurança.\nNao tratar exceções dentro do ator: se uma mensagem causar uma exceção não tratada, a coroutine do ator morre e todas as mensagens subsequentes serao perdidas. Sempre use try-catch dentro do loop.\nConfundir actor com Flow: Flow e para streams de dados reativos. Actor e para encapsular estado mutavel com acesso concorrente. São padrões complementares, não substitutos.\nActor vs Mutex Ambos resolvem o problema de acesso concorrente, mas de formas diferentes:\nMutex protege uma seção crítica. Qualquer coroutine pode acessar o estado diretamente, desde que adquira o lock. Actor encapsula o estado. Ninguem acessa diretamente; tudo passa por mensagens. O Actor tende a ser mais seguro em sistemas complexos porque elimina a possibilidade de alguem esquecer de usar o lock. Porem, o Mutex e mais simples para casos triviais.\nTermos relacionados Channel: o mecanismo de comunicação que os actors usam internamente para receber mensagens. Coroutine: a unidade de execução leve que implementa o ator. Mutex: alternativa para proteção de estado compartilhado, baseada em locks. Flow: stream reativo de dados, complementar ao padrão Actor. Dispatcher: controla em qual thread a coroutine do ator vai executar. Job: representa o ciclo de vida da coroutine que implementa o ator. O padrão Actor e uma ferramenta poderosa no arsenal de concorrência do Kotlin. Embora a função actor da biblioteca esteja marcada como obsoleta, o padrão em si continua sendo uma das formas mais seguras e organizadas de lidar com estado compartilhado em sistemas concorrentes.\n","permalink":"https://kotlin.dev.br/glossario/actor/","summary":"\u003ch2 id=\"o-que-é-actor-em-kotlin\"\u003eO que é Actor em Kotlin?\u003c/h2\u003e\n\u003cp\u003eO \u003cstrong\u003eActor\u003c/strong\u003e é um padrão de concorrência onde uma entidade isolada (o ator) recebe mensagens através de um canal, processa uma de cada vez e mantém seu próprio estado interno de forma segura. Em Kotlin, esse padrão e implementado com \u003cstrong\u003ecoroutines\u003c/strong\u003e e \u003cstrong\u003echannels\u003c/strong\u003e, aproveitando a infraestrutura do \u003ccode\u003ekotlinx.coroutines\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eA ideia central é simples: em vez de compartilhar estado entre várias threads e proteger com locks, você envia mensagens para um ator que é o único dono daquele estado. Como ele processa uma mensagem por vez, não há condições de corrida.\u003c/p\u003e","title":"Actor em Kotlin: O que É e Como Funciona | Kotlin Brasil"},{"content":"REST APIs são a espinha dorsal da comunicação entre sistemas modernos. Projetar APIs bem estruturadas, consistentes e documentadas é uma habilidade essencial para qualquer desenvolvedor backend. Kotlin, com sua expressividade e segurança de tipos, é uma excelente escolha para construir APIs que são ao mesmo tempo robustas e faceis de manter. Neste guia, vamos além do básico de rotas e controllers, abordando design de recursos, válidação, tratamento de erros, paginação, versionamento e documentação com OpenAPI.\nPrincipios de Design REST Uma API RESTful segue convenções que tornam o uso intuitivo para consumidores. Os principios fundamentais incluem: recursos identificados por URLs, verbos HTTP para operações, respostas com codigos de status apropriados e representacoes em JSON.\n// Bom design de URLs (recursos no plural, hierarquia clara) // GET /api/v1/clientes -\u0026gt; Listar clientes // GET /api/v1/clientes/{id} -\u0026gt; Buscar cliente // POST /api/v1/clientes -\u0026gt; Criar cliente // PUT /api/v1/clientes/{id} -\u0026gt; Atualizar cliente // DELETE /api/v1/clientes/{id} -\u0026gt; Remover cliente // GET /api/v1/clientes/{id}/pedidos -\u0026gt; Listar pedidos do cliente Estrutura de Projeto Uma API bem organizada separa responsabilidades em camadas:\n// Estrutura de pacotes // com.exemplo.api/ // controller/ -\u0026gt; Endpoints REST // service/ -\u0026gt; Logica de negocio // repository/ -\u0026gt; Acesso a dados // model/ // entity/ -\u0026gt; Entidades do banco // request/ -\u0026gt; DTOs de entrada // response/ -\u0026gt; DTOs de saida // config/ -\u0026gt; Configurações // exception/ -\u0026gt; Exceções e handlers // validation/ -\u0026gt; Validadores customizados DTOs Robustos com Validação Data classes do Kotlin combinadas com Bean Validation criam DTOs expressivos:\ndata class CriarClienteRequest( @field:NotBlank(message = \u0026#34;Nome e obrigatorio\u0026#34;) @field:Size(min = 2, max = 100, message = \u0026#34;Nome deve ter entre 2 e 100 caracteres\u0026#34;) val nome: String, @field:NotBlank(message = \u0026#34;Email e obrigatorio\u0026#34;) @field:Email(message = \u0026#34;Email invalido\u0026#34;) val email: String, @field:NotBlank(message = \u0026#34;CPF e obrigatorio\u0026#34;) @field:Pattern( regexp = \u0026#34;\\\\d{11}\u0026#34;, message = \u0026#34;CPF deve conter 11 digitos\u0026#34; ) val cpf: String, @field:Past(message = \u0026#34;Data de nascimento deve ser no passado\u0026#34;) val dataNascimento: LocalDate? = null, val endereco: EnderecoRequest? = null ) data class EnderecoRequest( @field:NotBlank(message = \u0026#34;CEP e obrigatorio\u0026#34;) @field:Pattern(regexp = \u0026#34;\\\\d{8}\u0026#34;, message = \u0026#34;CEP deve conter 8 digitos\u0026#34;) val cep: String, @field:NotBlank(message = \u0026#34;Logradouro e obrigatorio\u0026#34;) val logradouro: String, val numero: String? = null, val complemento: String? = null, @field:NotBlank(message = \u0026#34;Cidade e obrigatoria\u0026#34;) val cidade: String, @field:NotBlank(message = \u0026#34;UF e obrigatoria\u0026#34;) @field:Size(min = 2, max = 2, message = \u0026#34;UF deve ter 2 caracteres\u0026#34;) val uf: String ) data class ClienteResponse( val id: Long, val nome: String, val email: String, val cpf: String, val dataNascimento: LocalDate?, val endereco: EnderecoResponse?, val criadoEm: LocalDateTime, val atualizadoEm: LocalDateTime? ) // Response paginado generico data class PaginaResponse\u0026lt;T\u0026gt;( val conteudo: List\u0026lt;T\u0026gt;, val pagina: Int, val tamanho: Int, val totalElementos: Long, val totalPaginas: Int, val primeira: Boolean, val ultima: Boolean ) Controller Completo @RestController @RequestMapping(\u0026#34;/api/v1/clientes\u0026#34;) class ClienteController( private val clienteService: ClienteService ) { @GetMapping fun listar( @RequestParam(defaultValue = \u0026#34;0\u0026#34;) pagina: Int, @RequestParam(defaultValue = \u0026#34;20\u0026#34;) tamanho: Int, @RequestParam(defaultValue = \u0026#34;nome\u0026#34;) ordenarPor: String, @RequestParam(defaultValue = \u0026#34;ASC\u0026#34;) direcao: String, @RequestParam(required = false) busca: String? ): ResponseEntity\u0026lt;PaginaResponse\u0026lt;ClienteResponse\u0026gt;\u0026gt; { val resultado = clienteService.listar( pagina = pagina, tamanho = tamanho.coerceIn(1, 100), ordenarPor = ordenarPor, direcao = Sort.Direction.valueOf(direcao), busca = busca ) return ResponseEntity.ok(resultado) } @GetMapping(\u0026#34;/{id}\u0026#34;) fun buscar(@PathVariable id: Long): ResponseEntity\u0026lt;ClienteResponse\u0026gt; { val cliente = clienteService.buscarPorId(id) return ResponseEntity.ok(cliente) } @PostMapping fun criar( @Valid @RequestBody request: CriarClienteRequest ): ResponseEntity\u0026lt;ClienteResponse\u0026gt; { val cliente = clienteService.criar(request) val uri = URI.create(\u0026#34;/api/v1/clientes/${cliente.id}\u0026#34;) return ResponseEntity.created(uri).body(cliente) } @PutMapping(\u0026#34;/{id}\u0026#34;) fun atualizar( @PathVariable id: Long, @Valid @RequestBody request: AtualizarClienteRequest ): ResponseEntity\u0026lt;ClienteResponse\u0026gt; { val cliente = clienteService.atualizar(id, request) return ResponseEntity.ok(cliente) } @PatchMapping(\u0026#34;/{id}\u0026#34;) fun atualizarParcial( @PathVariable id: Long, @RequestBody campos: Map\u0026lt;String, Any?\u0026gt; ): ResponseEntity\u0026lt;ClienteResponse\u0026gt; { val cliente = clienteService.atualizarParcial(id, campos) return ResponseEntity.ok(cliente) } @DeleteMapping(\u0026#34;/{id}\u0026#34;) fun remover(@PathVariable id: Long): ResponseEntity\u0026lt;Void\u0026gt; { clienteService.remover(id) return ResponseEntity.noContent().build() } @GetMapping(\u0026#34;/{id}/pedidos\u0026#34;) fun listarPedidos( @PathVariable id: Long, @RequestParam(defaultValue = \u0026#34;0\u0026#34;) pagina: Int, @RequestParam(defaultValue = \u0026#34;20\u0026#34;) tamanho: Int ): ResponseEntity\u0026lt;PaginaResponse\u0026lt;PedidoResumoResponse\u0026gt;\u0026gt; { val pedidos = clienteService.listarPedidos(id, pagina, tamanho) return ResponseEntity.ok(pedidos) } } Tratamento Global de Erros Uma API profissional trata erros de forma consistente:\n@RestControllerAdvice class ApiExceptionHandler { @ExceptionHandler(RecursoNaoEncontradoException::class) fun handleNaoEncontrado( ex: RecursoNaoEncontradoException, request: HttpServletRequest ): ResponseEntity\u0026lt;ApiErro\u0026gt; { val erro = ApiErro( timestamp = Instant.now(), status = 404, erro = \u0026#34;Nao Encontrado\u0026#34;, mensagem = ex.message ?: \u0026#34;Recurso nao encontrado\u0026#34;, caminho = request.requestURI ) return ResponseEntity.status(404).body(erro) } @ExceptionHandler(MethodArgumentNotValidException::class) fun handleValidacao( ex: MethodArgumentNotValidException, request: HttpServletRequest ): ResponseEntity\u0026lt;ApiErro\u0026gt; { val violacoes = ex.bindingResult.fieldErrors.map { fieldError -\u0026gt; Violacao( campo = fieldError.field, mensagem = fieldError.defaultMessage ?: \u0026#34;Valor invalido\u0026#34;, valorRejeitado = fieldError.rejectedValue?.toString() ) } val erro = ApiErro( timestamp = Instant.now(), status = 400, erro = \u0026#34;Erro de Validação\u0026#34;, mensagem = \u0026#34;Um ou mais campos possuem valores invalidos\u0026#34;, caminho = request.requestURI, violacoes = violacoes ) return ResponseEntity.badRequest().body(erro) } @ExceptionHandler(ConflitoDeDadosException::class) fun handleConflito( ex: ConflitoDeDadosException, request: HttpServletRequest ): ResponseEntity\u0026lt;ApiErro\u0026gt; { val erro = ApiErro( timestamp = Instant.now(), status = 409, erro = \u0026#34;Conflito\u0026#34;, mensagem = ex.message ?: \u0026#34;Conflito de dados\u0026#34;, caminho = request.requestURI ) return ResponseEntity.status(409).body(erro) } @ExceptionHandler(Exception::class) fun handleErroInterno( ex: Exception, request: HttpServletRequest ): ResponseEntity\u0026lt;ApiErro\u0026gt; { val erro = ApiErro( timestamp = Instant.now(), status = 500, erro = \u0026#34;Erro Interno\u0026#34;, mensagem = \u0026#34;Ocorreu um erro interno no servidor\u0026#34;, caminho = request.requestURI ) return ResponseEntity.status(500).body(erro) } } data class ApiErro( val timestamp: Instant, val status: Int, val erro: String, val mensagem: String, val caminho: String, val violacoes: List\u0026lt;Violacao\u0026gt;? = null ) data class Violacao( val campo: String, val mensagem: String, val valorRejeitado: String? = null ) Filtragem e Busca Implemente filtragem flexivel usando specifications do Spring Data:\n@Service class ClienteService( private val repository: ClienteRepository ) { fun listar( pagina: Int, tamanho: Int, ordenarPor: String, direcao: Sort.Direction, busca: String? ): PaginaResponse\u0026lt;ClienteResponse\u0026gt; { val pageable = PageRequest.of(pagina, tamanho, Sort.by(direcao, ordenarPor)) val resultado = if (busca.isNullOrBlank()) { repository.findAll(pageable) } else { repository.buscar(busca, pageable) } return PaginaResponse( conteudo = resultado.content.map { it.toResponse() }, pagina = resultado.number, tamanho = resultado.size, totalElementos = resultado.totalElements, totalPaginas = resultado.totalPages, primeira = resultado.isFirst, ultima = resultado.isLast ) } } interface ClienteRepository : JpaRepository\u0026lt;Cliente, Long\u0026gt; { @Query(\u0026#34;\u0026#34;\u0026#34; SELECT c FROM Cliente c WHERE LOWER(c.nome) LIKE LOWER(CONCAT(\u0026#39;%\u0026#39;, :busca, \u0026#39;%\u0026#39;)) OR LOWER(c.email) LIKE LOWER(CONCAT(\u0026#39;%\u0026#39;, :busca, \u0026#39;%\u0026#39;)) \u0026#34;\u0026#34;\u0026#34;) fun buscar(busca: String, pageable: Pageable): Page\u0026lt;Cliente\u0026gt; } Documentação com OpenAPI Documente sua API automaticamente com SpringDoc:\n// build.gradle.kts dependencies { implementation(\u0026#34;org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0\u0026#34;) } // Configuração @Configuration class OpenApiConfig { @Bean fun customOpenAPI(): OpenAPI { return OpenAPI() .info( Info() .title(\u0026#34;API de Clientes\u0026#34;) .version(\u0026#34;1.0.0\u0026#34;) .description(\u0026#34;API para gerenciamento de clientes\u0026#34;) ) .addSecurityItem( SecurityRequirement().addList(\u0026#34;Bearer Authentication\u0026#34;) ) .components( Components().addSecuritySchemes( \u0026#34;Bearer Authentication\u0026#34;, SecurityScheme() .type(SecurityScheme.Type.HTTP) .bearerFormat(\u0026#34;JWT\u0026#34;) .scheme(\u0026#34;bearer\u0026#34;) ) ) } } Boas Práticas para REST APIs com Kotlin Use substantivos no plural para URLs: /clientes em vez de /cliente ou /getClientes. Retorne codigos HTTP apropriados: 201 para criação, 204 para delete, 400 para válidação, 404 para não encontrado. paginação obrigatória em listas: nunca retorne coleções sem limite. Sempre page. Versionamento desde o inicio: prefixe com /api/v1/ para permitir evolução sem quebrar clientes existentes. Respostas consistentes: toda resposta de erro deve seguir o mesmo formato. HATEOAS quando fizer sentido: inclua links para recursos relacionados para facilitar a navegação da API. Rate limiting: proteja sua API contra abuso com limites de requisicoes por cliente. Validação na borda: valide toda entrada no controller antes de processar. Erros Comuns e Armadilhas Verbos na URL: /api/getProdutos ou /api/criarCliente violam princípios REST. Use verbos HTTP com substantivos. Retornar 200 para erros: uma resposta com {\u0026quot;erro\u0026quot;: \u0026quot;não encontrado\u0026quot;} e status 200 confunde clientes. Use o código HTTP correto. Expor entidades internas: retornar a entidade JPA diretamente na resposta expõe detalhes internos e pode causar problemas de serialização com lazy loading. Ignorar idempotencia: PUT e DELETE devem ser idempotentes. Chamar DELETE duas vezes no mesmo recurso não deve causar erro. Listas sem paginação: retornar milhares de registros em uma única resposta causa problemas de performance e memória. Falta de documentação: uma API sem documentação e como uma biblioteca sem indice. Use OpenAPI/Swagger. Conclusão e Próximos Passos Construir REST APIs profissionais com Kotlin vai além de criar endpoints que funcionam. Envolve design cuidadoso de recursos, tratamento consistente de erros, válidação robusta, documentação clara e atencao a performance. Com as práticas apresentadas neste guia, você tem a base para criar APIs que são um prazer de consumir. Explore nossos guias sobre testes para garantir a qualidade da API, autenticação com JWT para segurança e microsserviços para arquiteturas mais complexas. Para uma visão comparativa, veja como construir APIs REST em Go e Python com FastAPI.\n","permalink":"https://kotlin.dev.br/guias/guia-kotlin-rest-api/","summary":"\u003cp\u003eREST APIs são a espinha dorsal da comunicação entre sistemas modernos. Projetar APIs bem estruturadas, consistentes e documentadas é uma habilidade essencial para qualquer desenvolvedor backend. Kotlin, com sua expressividade e segurança de tipos, é uma excelente escolha para construir APIs que são ao mesmo tempo robustas e faceis de manter. Neste guia, vamos além do básico de rotas e controllers, abordando design de recursos, válidação, tratamento de erros, paginação, versionamento e documentação com OpenAPI.\u003c/p\u003e","title":"REST APIs com Kotlin: Guia Completo em Português | Kotlin Brasil"},{"content":"Preparar-se para entrevistas tecnicas com Kotlin exige conhecer não apenas a sintaxe, mas também os conceitos por tras das decisoes de design da linguagem. Neste guia, compilamos as perguntas mais frequentes em processos seletivos, com respostas detalhadas e exemplos práticos.\nPerguntas sobre Fundamentos 1. Qual a diferenca entre val e var? Esta e quase sempre a primeira pergunta. A resposta vai além do básico:\nval nome = \u0026#34;Kotlin\u0026#34; // Referência imutavel (similar a final em Java) var contador = 0 // Referência mutavel // Importante: val nao significa que o OBJETO e imutavel val lista = mutableListOf(1, 2, 3) lista.add(4) // Funciona! A referência nao muda, mas o conteudo sim // Para imutabilidade real, use coleções imutáveis val listaImutavel = listOf(1, 2, 3) // listaImutavel.add(4) // Nao compila! O ponto chave e explicar que val torna a referência imutavel, não o objeto em si. Para imutabilidade profunda, você precisa usar tipos imutáveis.\n2. Explique Null Safety em Kotlin // Tipos nullable vs non-nullable var nome: String = \u0026#34;Kotlin\u0026#34; // Nao pode ser null var apelido: String? = null // Pode ser null // Operadores de null safety val tamanho1: Int? = apelido?.length // Safe call val tamanho2: Int = apelido?.length ?: 0 // Elvis operator val tamanho3: Int = apelido!!.length // Not-null assertion (perigoso) // Smart cast fun processar(valor: String?) { if (valor != null) { // Aqui, valor e automaticamente String (nao String?) println(valor.length) } } // let para trabalhar com nullables apelido?.let { nomeNaoNulo -\u0026gt; println(\u0026#34;Apelido: $nomeNaoNulo\u0026#34;) println(\u0026#34;Tamanho: ${nomeNaoNulo.length}\u0026#34;) } Mencione que null safety elimina NullPointerException em tempo de compilação, e que o operador !! deve ser evitado em código de producao.\n3. O que são Data Classes? data class Usuario( val id: String, val nome: String, val email: String, val ativo: Boolean = true ) // O compilador gera automaticamente: // - equals() e hashCode() baseados nas propriedades do construtor primario // - toString() formatado // - copy() para criar copias com modificacoes // - componentN() para destructuring val user = Usuario(\u0026#34;1\u0026#34;, \u0026#34;Ana\u0026#34;, \u0026#34;ana@email.com\u0026#34;) val copia = user.copy(nome = \u0026#34;Maria\u0026#34;) // Destructuring val (id, nome, email) = user println(\u0026#34;$nome ($email)\u0026#34;) // Util em coleções val usuarios = listOf(user, copia) val nomes = usuarios.map { (_, nome, _) -\u0026gt; nome } 4. Sealed Classes vs Enum Classes // Enum - Conjunto fixo de constantes enum class Cor { VERMELHO, VERDE, AZUL } // Sealed class - Hierarquia restrita com dados diferentes por tipo sealed class Resultado { data class Sucesso(val dados: String) : Resultado() data class Erro(val mensagem: String, val codigo: Int) : Resultado() data object Carregando : Resultado() } fun tratar(resultado: Resultado): String { return when (resultado) { is Resultado.Sucesso -\u0026gt; \u0026#34;OK: ${resultado.dados}\u0026#34; is Resultado.Erro -\u0026gt; \u0026#34;Erro ${resultado.codigo}: ${resultado.mensagem}\u0026#34; is Resultado.Carregando -\u0026gt; \u0026#34;Aguarde...\u0026#34; } // O when e EXAUSTIVO - o compilador verifica todos os casos } A diferenca chave: enums tem instancias fixas e identicas em estrutura, sealed classes permitem subtipos diferentes com dados diferentes.\nPerguntas sobre Coroutines 5. O que são Coroutines e como funcionam? // Coroutines são threads leves gerenciadas pelo Kotlin // Uma suspend function so pode ser chamada de outra suspend function // ou de um coroutine builder suspend fun buscarDados(): List\u0026lt;String\u0026gt; { delay(1000) // Suspende sem bloquear a thread return listOf(\u0026#34;dado1\u0026#34;, \u0026#34;dado2\u0026#34;) } // Coroutine builders fun exemplo(scope: CoroutineScope) { // launch - Fire and forget, retorna Job scope.launch { val dados = buscarDados() processar(dados) } // async - Retorna Deferred com resultado scope.launch { val deferred = async { buscarDados() } val dados = deferred.await() } // runBlocking - Bloqueia a thread atual (usar apenas em testes/main) runBlocking { val dados = buscarDados() } } 6. Explique Dispatchers e Structured Concurrency // Dispatchers controlam em qual thread a coroutine executa suspend fun exemploDispatchers() { // Dispatchers.Main - Thread principal (UI no Android) // Dispatchers.IO - Otimizado para I/O (rede, disco) // Dispatchers.Default - Otimizado para CPU withContext(Dispatchers.IO) { // Operações de rede ou banco de dados aqui } withContext(Dispatchers.Default) { // Calculos pesados aqui } } // Structured concurrency garante que coroutines filhas // são canceladas quando o escopo pai e cancelado suspend fun buscarTudo() = coroutineScope { val usuarios = async { api.getUsuarios() } val produtos = async { api.getProdutos() } // Se api.getUsuarios() falhar, api.getProdutos() e cancelado automaticamente Pair(usuarios.await(), produtos.await()) } 7. Qual a diferenca entre Flow, StateFlow e SharedFlow? // Flow - Stream frio (cold), emite valores sob demanda fun temperaturas(): Flow\u0026lt;Double\u0026gt; = flow { while (true) { emit(sensor.lerTemperatura()) delay(1000) } } // StateFlow - Sempre tem um valor atual, hot stream class ContadorViewModel : ViewModel() { private val _contagem = MutableStateFlow(0) val contagem: StateFlow\u0026lt;Int\u0026gt; = _contagem.asStateFlow() fun incrementar() { _contagem.update { it + 1 } } } // SharedFlow - Hot stream sem valor inicial, configuracel class EventBus { private val _eventos = MutableSharedFlow\u0026lt;Evento\u0026gt;( replay = 0, extraBufferCapacity = 64, onBufferOverflow = BufferOverflow.DROP_OLDEST ) val eventos: SharedFlow\u0026lt;Evento\u0026gt; = _eventos.asSharedFlow() suspend fun emitir(evento: Evento) { _eventos.emit(evento) } } Perguntas sobre Funções 8. Extension Functions e Scope Functions // Extension functions adicionam funcionalidades a tipos existentes fun String.isValidEmail(): Boolean { return matches(Regex(\u0026#34;^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$\u0026#34;)) } val valido = \u0026#34;user@email.com\u0026#34;.isValidEmail() // true // Scope functions: let, run, with, apply, also data class Configuração( var host: String = \u0026#34;\u0026#34;, var porta: Int = 0, var timeout: Long = 0 ) // apply - Configura um objeto e retorna ele mesmo val config = Configuração().apply { host = \u0026#34;localhost\u0026#34; porta = 8080 timeout = 5000 } // let - Transforma valor, util com nullables val resultado = texto?.let { it.trim().uppercase() } // also - Executa acao lateral, retorna o objeto original val lista = mutableListOf(1, 2, 3).also { println(\u0026#34;Lista criada com ${it.size} elementos\u0026#34;) } // run - Executa bloco no contexto do objeto, retorna resultado val tamanhoFormatado = texto.run { trim() \u0026#34;Texto tem $length caracteres\u0026#34; } 9. Higher-Order Functions e Lambdas // Higher-order function recebe ou retorna funcoes fun \u0026lt;T\u0026gt; List\u0026lt;T\u0026gt;.customFilter( predicate: (T) -\u0026gt; Boolean ): List\u0026lt;T\u0026gt; { val resultado = mutableListOf\u0026lt;T\u0026gt;() for (item in this) { if (predicate(item)) { resultado.add(item) } } return resultado } // Uso val pares = listOf(1, 2, 3, 4, 5).customFilter { it % 2 == 0 } // inline - Evita overhead de criacao de objetos lambda inline fun \u0026lt;T\u0026gt; medirTempo(bloco: () -\u0026gt; T): Pair\u0026lt;T, Long\u0026gt; { val inicio = System.currentTimeMillis() val resultado = bloco() val duracao = System.currentTimeMillis() - inicio return Pair(resultado, duracao) } Perguntas de Design e Arquitetura 10. Como você estrutura um projeto Kotlin? // Clean Architecture tipica // domain/ - Regras de negocio puras // model/ // repository/ (interfaces) // usecase/ // data/ - Implementacoes de acesso a dados // repository/ (implementacoes) // remote/ // local/ // presentation/ - UI e ViewModels // screen/ // viewmodel/ // component/ // Exemplo de Use Case class TransferirDinheiroUseCase( private val contaRepository: ContaRepository, private val transacaoRepository: TransacaoRepository ) { suspend operator fun invoke( origem: ContaId, destino: ContaId, valor: Money ): Result\u0026lt;Transacao\u0026gt; = runCatching { require(valor.isPositive()) { \u0026#34;Valor deve ser positivo\u0026#34; } val contaOrigem = contaRepository.buscar(origem) ?: throw ContaNaoEncontradaException(origem) require(contaOrigem.saldo \u0026gt;= valor) { \u0026#34;Saldo insuficiente\u0026#34; } val transacao = Transacao( origem = origem, destino = destino, valor = valor, timestamp = Instant.now() ) contaRepository.debitar(origem, valor) contaRepository.creditar(destino, valor) transacaoRepository.salvar(transacao) } } Dicas para a Entrevista Explique seu raciocinio: Nao apenas de a resposta, explique por que Mencione trade-offs: Mostra maturidade técnica Use exemplos reais: Relacione conceitos com situacoes práticas Admita quando não sabe: E muito melhor que inventar uma resposta Faca perguntas: Mostra interesse genuino na empresa e no projeto Conclusão Preparar-se para entrevistas Kotlin vai além de decorar respostas. O objetivo e demonstrar que você entende os conceitos profundamente e sabe aplica-los em cenários reais. Entrevistadores frequentemente perguntam como Kotlin se compara a outras linguagens — conhecer Go, Rust ou Python demonstra amplitude técnica. Pratique escrevendo código, revise os conceitos fundamentais e mantenha-se atualizado com as novidades da linguagem. Com preparacao adequada, você estara confiante para enfrentar qualquer processo seletivo.\n","permalink":"https://kotlin.dev.br/blog/entrevista-kotlin-perguntas/","summary":"\u003cp\u003ePreparar-se para entrevistas tecnicas com Kotlin exige conhecer não apenas a sintaxe, mas também os conceitos por tras das decisoes de design da linguagem. Neste guia, compilamos as perguntas mais frequentes em processos seletivos, com respostas detalhadas e exemplos práticos.\u003c/p\u003e\n\u003ch2 id=\"perguntas-sobre-fundamentos\"\u003ePerguntas sobre Fundamentos\u003c/h2\u003e\n\u003ch3 id=\"1-qual-a-diferenca-entre-val-e-var\"\u003e1. Qual a diferenca entre val e var?\u003c/h3\u003e\n\u003cp\u003eEsta e quase sempre a primeira pergunta. A resposta vai além do básico:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003enome\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Kotlin\u0026#34;\u003c/span\u003e   \u003cspan class=\"c1\"\u003e// Referência imutavel (similar a final em Java)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003evar\u003c/span\u003e \u003cspan class=\"py\"\u003econtador\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e      \u003cspan class=\"c1\"\u003e// Referência mutavel\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Importante: val nao significa que o OBJETO e imutavel\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003elista\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emutableListOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003elista\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e  \u003cspan class=\"c1\"\u003e// Funciona! A referência nao muda, mas o conteudo sim\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Para imutabilidade real, use coleções imutáveis\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eval\u003c/span\u003e \u003cspan class=\"py\"\u003elistaImutavel\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003elistOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// listaImutavel.add(4)  // Nao compila!\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eO ponto chave e explicar que \u003ccode\u003eval\u003c/code\u003e torna a referência imutavel, não o objeto em si. Para imutabilidade profunda, você precisa usar tipos imutáveis.\u003c/p\u003e","title":"Perguntas de Entrevista Kotlin: Guia Completo de Preparacao | Kotlin Brasil"},{"content":"Uma das funcionalidades mais poderosas do Kotlin é a capacidade de criar Domain-Specific Languages (DSLs) — mini-linguagens especializadas que tornam o código mais expressivo e legível. Neste tutorial, vamos explorar todos os recursos que fazem isso possível: builder pattern, lambda with receiver, a annotation @DslMarker, type-safe builders, e construir exemplos práticos do zero. Também vamos entender como o Gradle utiliza esses mesmos conceitos internamente.\nO que é uma DSL? Uma DSL (Domain-Specific Language) é uma linguagem projetada para um domínio específico. Diferente de uma linguagem de propósito geral como Kotlin ou Java, uma DSL oferece uma sintaxe focada que se lê quase como linguagem natural para aquele contexto. Exemplos clássicos incluem SQL para consultas a banco de dados, HTML para markup e expressões regulares para padrões de texto.\nEm Kotlin, podemos criar DSLs internas — código Kotlin válido que se parece com uma linguagem customizada graças a recursos como extension functions, lambdas com receiver, operadores infix e conventions de nomeação. O resultado é uma API que é ao mesmo tempo type-safe e extremamente legível.\nPasso 1: Entendendo Lambda with Receiver O alicerce de qualquer DSL em Kotlin é a lambda with receiver. É uma lambda que executa no contexto de um objeto receptor, permitindo acessar suas propriedades e métodos sem qualificação:\n// Tipo da lambda: StringBuilder.() -\u0026gt; Unit fun construirString(bloco: StringBuilder.() -\u0026gt; Unit): String { val sb = StringBuilder() sb.bloco() // ou bloco(sb) return sb.toString() } val resultado = construirString { append(\u0026#34;Olá, \u0026#34;) // \u0026#39;this\u0026#39; e o StringBuilder append(\u0026#34;Kotlin \u0026#34;) append(\u0026#34;Brasil!\u0026#34;) } println(resultado) // Olá, Kotlin Brasil! Dentro da lambda, this referência o StringBuilder. Como Kotlin permite omitir this, chamamos append() diretamente, criando uma sintaxe limpa e fluente. Esse é exatamente o padrão usado por apply, with e run da biblioteca padrão.\nPasso 2: Builder Pattern com Lambdas Vamos construir um builder para configurar um servidor HTTP. Primeiro, definimos as classes de dados:\ndata class ConfigServidor( val host: String, val porta: Int, val ssl: ConfigSSL?, val rotas: List\u0026lt;Rota\u0026gt; ) data class ConfigSSL( val certificado: String, val chavePrivada: String ) data class Rota( val caminho: String, val metodo: String, val handler: String ) Agora, criamos os builders com lambdas with receiver:\nclass ServidorBuilder { var host: String = \u0026#34;localhost\u0026#34; var porta: Int = 8080 private var ssl: ConfigSSL? = null private val rotas = mutableListOf\u0026lt;Rota\u0026gt;() fun ssl(bloco: SSLBuilder.() -\u0026gt; Unit) { ssl = SSLBuilder().apply(bloco).build() } fun rota(caminho: String, metodo: String = \u0026#34;GET\u0026#34;, handler: String) { rotas.add(Rota(caminho, metodo, handler)) } fun rotas(bloco: RotasBuilder.() -\u0026gt; Unit) { RotasBuilder(rotas).apply(bloco) } fun build(): ConfigServidor = ConfigServidor(host, porta, ssl, rotas) } class SSLBuilder { var certificado: String = \u0026#34;\u0026#34; var chavePrivada: String = \u0026#34;\u0026#34; fun build(): ConfigSSL = ConfigSSL(certificado, chavePrivada) } class RotasBuilder(private val rotas: MutableList\u0026lt;Rota\u0026gt;) { fun get(caminho: String, handler: String) { rotas.add(Rota(caminho, \u0026#34;GET\u0026#34;, handler)) } fun post(caminho: String, handler: String) { rotas.add(Rota(caminho, \u0026#34;POST\u0026#34;, handler)) } fun delete(caminho: String, handler: String) { rotas.add(Rota(caminho, \u0026#34;DELETE\u0026#34;, handler)) } } fun servidor(bloco: ServidorBuilder.() -\u0026gt; Unit): ConfigServidor { return ServidorBuilder().apply(bloco).build() } O uso final fica limpo e expressivo:\nval config = servidor { host = \u0026#34;api.kotlinbrasil.com\u0026#34; porta = 443 ssl { certificado = \u0026#34;/certs/server.crt\u0026#34; chavePrivada = \u0026#34;/certs/server.key\u0026#34; } rotas { get(\u0026#34;/api/usuarios\u0026#34;, \u0026#34;UsuarioController::listar\u0026#34;) post(\u0026#34;/api/usuarios\u0026#34;, \u0026#34;UsuarioController::criar\u0026#34;) delete(\u0026#34;/api/usuarios/{id}\u0026#34;, \u0026#34;UsuarioController::remover\u0026#34;) } } Esse código parece uma linguagem de configuração dedicada, mas é Kotlin puro, com verificação de tipos e autocompletion do IDE.\nPasso 3: @DslMarker para Escopo Controlado Um problema com DSLs aninhadas é que lambdas internas podem acessar receivers externos, causando confusão. A annotation @DslMarker resolve isso restringindo o escopo:\n@DslMarker annotation class HtmlDsl @HtmlDsl class HTML { private val children = mutableListOf\u0026lt;HtmlElement\u0026gt;() fun head(bloco: Head.() -\u0026gt; Unit) { children.add(Head().apply(bloco)) } fun body(bloco: Body.() -\u0026gt; Unit) { children.add(Body().apply(bloco)) } override fun toString(): String = \u0026#34;\u0026lt;html\u0026gt;\\n${children.joinToString(\u0026#34;\\n\u0026#34;)}\\n\u0026lt;/html\u0026gt;\u0026#34; } @HtmlDsl class Head : HtmlElement { var titulo: String = \u0026#34;\u0026#34; fun title(texto: String) { titulo = texto } override fun toString(): String = \u0026#34; \u0026lt;head\u0026gt;\\n \u0026lt;title\u0026gt;$titulo\u0026lt;/title\u0026gt;\\n \u0026lt;/head\u0026gt;\u0026#34; } @HtmlDsl class Body : HtmlElement { private val elementos = mutableListOf\u0026lt;String\u0026gt;() fun h1(texto: String) { elementos.add(\u0026#34; \u0026lt;h1\u0026gt;$texto\u0026lt;/h1\u0026gt;\u0026#34;) } fun p(texto: String) { elementos.add(\u0026#34; \u0026lt;p\u0026gt;$texto\u0026lt;/p\u0026gt;\u0026#34;) } fun div(bloco: Body.() -\u0026gt; Unit) { val inner = Body().apply(bloco) elementos.add(\u0026#34; \u0026lt;div\u0026gt;\\n${inner.elementos.joinToString(\u0026#34;\\n\u0026#34;) { \u0026#34; $it\u0026#34; }}\\n \u0026lt;/div\u0026gt;\u0026#34;) } override fun toString(): String = \u0026#34; \u0026lt;body\u0026gt;\\n${elementos.joinToString(\u0026#34;\\n\u0026#34;)}\\n \u0026lt;/body\u0026gt;\u0026#34; } interface HtmlElement fun html(bloco: HTML.() -\u0026gt; Unit): HTML = HTML().apply(bloco) Com @DslMarker, dentro do bloco body { } você não pode acessar diretamente os métodos de HTML. Isso previne erros como chamar head { } dentro de body { }:\nval pagina = html { head { title(\u0026#34;Kotlin Brasil\u0026#34;) // body { } // ERRO de compilacao! @DslMarker impede isso } body { h1(\u0026#34;Bem-vindo ao Kotlin Brasil\u0026#34;) p(\u0026#34;Aprenda Kotlin em português\u0026#34;) div { p(\u0026#34;Conteúdo dentro de uma div\u0026#34;) // head { } // ERRO! Não está no escopo de HTML } } } println(pagina) O @DslMarker é essencial para DSLs robustas. Se realmente precisar acessar um receiver externo, use this@html explicitamente.\nPasso 4: DSL de Configuração Prática Vamos criar uma DSL para configuração de aplicação, um caso de uso muito comum em projetos reais:\n@DslMarker annotation class ConfigDsl @ConfigDsl class AppConfig { var nome: String = \u0026#34;\u0026#34; var versao: String = \u0026#34;1.0.0\u0026#34; var ambiente: String = \u0026#34;desenvolvimento\u0026#34; private var _banco: BancoConfig? = null private var _cache: CacheConfig? = null private val _features = mutableMapOf\u0026lt;String, Boolean\u0026gt;() fun banco(bloco: BancoConfig.() -\u0026gt; Unit) { _banco = BancoConfig().apply(bloco) } fun cache(bloco: CacheConfig.() -\u0026gt; Unit) { _cache = CacheConfig().apply(bloco) } fun features(bloco: FeatureFlags.() -\u0026gt; Unit) { FeatureFlags(_features).apply(bloco) } fun build(): Map\u0026lt;String, Any?\u0026gt; = mapOf( \u0026#34;nome\u0026#34; to nome, \u0026#34;versao\u0026#34; to versao, \u0026#34;ambiente\u0026#34; to ambiente, \u0026#34;banco\u0026#34; to _banco, \u0026#34;cache\u0026#34; to _cache, \u0026#34;features\u0026#34; to _features ) } @ConfigDsl class BancoConfig { var url: String = \u0026#34;jdbc:postgresql://localhost:5432/app\u0026#34; var usuario: String = \u0026#34;postgres\u0026#34; var senha: String = \u0026#34;\u0026#34; var poolSize: Int = 10 var timeout: Long = 30_000 } @ConfigDsl class CacheConfig { var provedor: String = \u0026#34;redis\u0026#34; var host: String = \u0026#34;localhost\u0026#34; var porta: Int = 6379 var ttlSegundos: Long = 3600 } @ConfigDsl class FeatureFlags(private val flags: MutableMap\u0026lt;String, Boolean\u0026gt;) { infix fun String.habilitada(valor: Boolean) { flags[this] = valor } } fun appConfig(bloco: AppConfig.() -\u0026gt; Unit): Map\u0026lt;String, Any?\u0026gt; { return AppConfig().apply(bloco).build() } O uso dessa DSL demonstra como a configuração se torna autodocumentada:\nval config = appConfig { nome = \u0026#34;Kotlin Brasil API\u0026#34; versao = \u0026#34;2.1.0\u0026#34; ambiente = \u0026#34;producao\u0026#34; banco { url = \u0026#34;jdbc:postgresql://db.exemplo.com:5432/producao\u0026#34; usuario = \u0026#34;app_user\u0026#34; senha = System.getenv(\u0026#34;DB_SENHA\u0026#34;) ?: \u0026#34;\u0026#34; poolSize = 20 timeout = 15_000 } cache { provedor = \u0026#34;redis\u0026#34; host = \u0026#34;cache.exemplo.com\u0026#34; ttlSegundos = 1800 } features { \u0026#34;novo-dashboard\u0026#34; habilitada true \u0026#34;beta-relatorios\u0026#34; habilitada false \u0026#34;notificacoes-push\u0026#34; habilitada true } } Note o uso da função infix para habilitada, criando uma sintaxe natural para feature flags. Funções infix eliminam a necessidade de ponto e parênteses, aproximando o código de prosa.\nPasso 5: Como o Gradle DSL Funciona Internamente O build.gradle.kts que usamos diariamente é construído exatamente com essas técnicas. Vamos desmistificar:\n// Simplificação do que o Gradle faz internamente class Project { fun dependencies(bloco: DependencyHandler.() -\u0026gt; Unit) { DependencyHandler().apply(bloco) } fun repositories(bloco: RepositoryHandler.() -\u0026gt; Unit) { RepositoryHandler().apply(bloco) } } class DependencyHandler { fun implementation(dependencia: String) { println(\u0026#34;Adicionando: $dependencia ao classpath de compilacao\u0026#34;) } fun testImplementation(dependencia: String) { println(\u0026#34;Adicionando: $dependencia ao classpath de teste\u0026#34;) } } class RepositoryHandler { fun mavenCentral() { println(\u0026#34;Repositório: Maven Central\u0026#34;) } fun google() { println(\u0026#34;Repositório: Google\u0026#34;) } } Quando você escreve dependencies { implementation(\u0026quot;...\u0026quot;) } no Gradle, está usando exatamente o mesmo padrão de lambda with receiver que construímos neste tutorial. O bloco plugins { }, repositories { }, tasks { } — todos seguem esse padrão. Agora você entende a magia por trás do build.gradle.kts.\nErros Comuns 1. Não usar @DslMarker: Sem ele, DSLs aninhadas permitem acessar receivers de escopos externos, levando a configurações incorretas que compilam sem erros. Sempre crie uma annotation marcada com @DslMarker para sua DSL.\n2. Builders mutáveis expostos: Nunca exponha o builder diretamente como resultado. Sempre crie um método build() que retorna um objeto imutável (data class ou similar). Isso garante que a configuração não pode ser alterada após a construção.\n3. Excesso de DSL: Nem tudo precisa ser uma DSL. Use DSLs quando a mesma estrutura será configurada repetidamente e a legibilidade é crítica. Para configurações simples, um construtor com parâmetros nomeados pode ser suficiente.\n4. Esquecer de chamar apply: Um erro sutil é escrever Builder().bloco() ao invés de Builder().apply(bloco). Com apply, o this dentro da lambda é o Builder. Sem ele, dependendo do tipo da lambda, o comportamento pode ser diferente.\n5. Lambda with receiver vs lambda comum: (String) -\u0026gt; Unit e String.() -\u0026gt; Unit são tipos diferentes. O primeiro recebe String como parâmetro, o segundo usa String como receiver. Confundir os dois causa erros de tipo difíceis de diagnosticar para iniciantes.\nConclusão e Próximos Passos Neste tutorial, exploramos os fundamentos de DSLs em Kotlin: lambdas with receiver para contextos fluentes, builder pattern para construção declarativa, @DslMarker para escopo seguro, funções infix para sintaxe natural e type-safe builders para configurações robustas. Esses conceitos são a espinha dorsal de bibliotecas como Ktor, Gradle, Compose e Exposed.\nComo próximos passos, experimente criar uma DSL para o domínio do seu projeto — seja para configuração de testes, definição de rotas de API ou regras de válidação. Estude o código-fonte do Ktor e do Compose para ver como DSLs são usadas em escala de produção. Confira também nosso tutorial sobre Gradle com Kotlin DSL para ver essas técnicas aplicadas no sistema de build, e o glossário de DSL para uma referência rápida do conceito.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-dsl-tutorial/","summary":"\u003cp\u003eUma das funcionalidades mais poderosas do Kotlin é a capacidade de criar \u003cstrong\u003eDomain-Specific Languages\u003c/strong\u003e (DSLs) — mini-linguagens especializadas que tornam o código mais expressivo e legível. Neste tutorial, vamos explorar todos os recursos que fazem isso possível: builder pattern, \u003ca href=\"/glossario/lambda/\"\u003elambda\u003c/a\u003e with receiver, a annotation \u003ccode\u003e@DslMarker\u003c/code\u003e, type-safe builders, e construir exemplos práticos do zero. Também vamos entender como o Gradle utiliza esses mesmos conceitos internamente.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-uma-dsl\"\u003eO que é uma DSL?\u003c/h2\u003e\n\u003cp\u003eUma \u003ca href=\"/glossario/dsl/\"\u003eDSL\u003c/a\u003e (Domain-Specific Language) é uma linguagem projetada para um domínio específico. Diferente de uma linguagem de propósito geral como Kotlin ou Java, uma DSL oferece uma sintaxe focada que se lê quase como linguagem natural para aquele contexto. Exemplos clássicos incluem SQL para consultas a banco de dados, HTML para markup e expressões regulares para padrões de texto.\u003c/p\u003e","title":"Kotlin DSL Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Microsserviços representam uma abordagem arquitetural onde uma aplicação e dividida em serviços pequenos, independentes e especializados, cada um responsavel por uma capacidade de negócio específica. Kotlin se destaca nesse cenário gracas ao suporte nativo a coroutines para comunicação assíncrona, sintaxe concisa que reduz boilerplate e compatibilidade total com o ecossistema JVM. Neste guia, vamos projetar e implementar uma arquitetura de microsserviços com Kotlin, abordando comunicação entre serviços, resiliência, observabilidade e estrategias de deploy.\nQuando Usar Microsserviços Microsserviços não são a solução para todos os problemas. Eles adicionam complexidade operacional significativa e só fazem sentido quando o projeto tem equipes grandes trabalhando em paralelo, necessidade de escalar componentes independentemente ou dominios de negócio claramente separados.\nPara projetos pequenos com uma única equipe, um monolito bem estruturado com Clean Architecture e geralmente mais eficiente. Migre para microsserviços quando a complexidade organizacional justificar.\nArquitetura de Referência Vamos implementar um sistema de e-commerce com tres microsserviços: Catálogo, Pedidos e Notificacoes.\n// Estrutura de repositórios // catálogo-service/ -\u0026gt; Gerencia produtos e categorias // pedidos-service/ -\u0026gt; Processa pedidos e pagamentos // notificacoes-service/ -\u0026gt; Envia emails e push notifications // api-gateway/ -\u0026gt; Ponto de entrada unificado Serviço de Catálogo com Ktor // catálogo-service/src/main/kotlin/Application.kt fun main() { embeddedServer(Netty, port = 8081) { configurarPlugins() configurarRoutes() }.start(wait = true) } fun Application.configurarPlugins() { install(ContentNegotiation) { json(Json { prettyPrint = true ignoreUnknownKeys = true }) } install(StatusPages) { exception\u0026lt;Throwable\u0026gt; { call, causa -\u0026gt; call.respond( HttpStatusCode.InternalServerError, ErroResponse(\u0026#34;Erro interno: ${causa.message}\u0026#34;) ) } } } fun Application.configurarRoutes() { val service = CatalogoService() routing { route(\u0026#34;/api/produtos\u0026#34;) { get { val produtos = service.listarProdutos() call.respond(produtos) } get(\u0026#34;/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toLongOrNull() ?: return@get call.respond( HttpStatusCode.BadRequest, ErroResponse(\u0026#34;ID invalido\u0026#34;) ) val produto = service.buscarPorId(id) ?: return@get call.respond( HttpStatusCode.NotFound, ErroResponse(\u0026#34;Produto nao encontrado\u0026#34;) ) call.respond(produto) } get(\u0026#34;/{id}/disponibilidade\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toLongOrNull() ?: return@get call.respond( HttpStatusCode.BadRequest, ErroResponse(\u0026#34;ID invalido\u0026#34;) ) val disponibilidade = service.verificarDisponibilidade(id) call.respond(disponibilidade) } } get(\u0026#34;/health\u0026#34;) { call.respond(mapOf(\u0026#34;status\u0026#34; to \u0026#34;UP\u0026#34;, \u0026#34;serviço\u0026#34; to \u0026#34;catálogo\u0026#34;)) } } } Serviço de Pedidos com Spring Boot // pedidos-service @SpringBootApplication class PedidosApplication fun main(args: Array\u0026lt;String\u0026gt;) { runApplication\u0026lt;PedidosApplication\u0026gt;(*args) } @RestController @RequestMapping(\u0026#34;/api/pedidos\u0026#34;) class PedidoController( private val pedidoService: PedidoService ) { @PostMapping @ResponseStatus(HttpStatus.CREATED) suspend fun criarPedido( @Valid @RequestBody request: CriarPedidoRequest ): PedidoResponse { return pedidoService.criarPedido(request) } @GetMapping(\u0026#34;/{id}\u0026#34;) suspend fun buscarPedido(@PathVariable id: Long): PedidoResponse { return pedidoService.buscarPorId(id) } @GetMapping(\u0026#34;/cliente/{clienteId}\u0026#34;) suspend fun listarPorCliente( @PathVariable clienteId: Long ): List\u0026lt;PedidoResponse\u0026gt; { return pedidoService.listarPorCliente(clienteId) } } @Service class PedidoService( private val catalogoClient: CatalogoClient, private val notificacaoClient: NotificacaoClient, private val pedidoRepository: PedidoRepository ) { suspend fun criarPedido(request: CriarPedidoRequest): PedidoResponse { // Verificar disponibilidade no serviço de catálogo for (item in request.itens) { val disponibilidade = catalogoClient.verificarDisponibilidade( item.produtoId ) if (disponibilidade.quantidade \u0026lt; item.quantidade) { throw NegocioException( \u0026#34;Produto ${item.produtoId} sem estoque suficiente\u0026#34; ) } } // Buscar detalhes dos produtos val itensCompletos = request.itens.map { item -\u0026gt; val produto = catalogoClient.buscarProduto(item.produtoId) ItemPedido( produtoId = produto.id, nomeProduto = produto.nome, quantidade = item.quantidade, precoUnitario = produto.preco ) } // Salvar pedido val pedido = Pedido( clienteId = request.clienteId, itens = itensCompletos, status = StatusPedido.PENDENTE ) val pedidoSalvo = pedidoRepository.save(pedido) // Notificar de forma assíncrona coroutineScope { launch { notificacaoClient.enviarNotificacao( NotificacaoRequest( destinatario = request.emailCliente, tipo = \u0026#34;PEDIDO_CRIADO\u0026#34;, dados = mapOf(\u0026#34;pedidoId\u0026#34; to pedidoSalvo.id.toString()) ) ) } } return pedidoSalvo.toResponse() } } Comunicação entre Serviços Cliente HTTP com Resiliência @Component class CatalogoClient( private val httpClient: HttpClient ) { private val baseUrl = System.getenv(\u0026#34;CATALOGO_SERVICE_URL\u0026#34;) ?: \u0026#34;http://catálogo-service:8081\u0026#34; suspend fun buscarProduto(id: Long): ProdutoDto { return comRetry(tentativas = 3) { httpClient.get(\u0026#34;$baseUrl/api/produtos/$id\u0026#34;).body() } } suspend fun verificarDisponibilidade(produtoId: Long): DisponibilidadeDto { return comRetry(tentativas = 3) { httpClient.get( \u0026#34;$baseUrl/api/produtos/$produtoId/disponibilidade\u0026#34; ).body() } } } // Função de retry generica suspend fun \u0026lt;T\u0026gt; comRetry( tentativas: Int = 3, delayInicial: Long = 500L, fatorMultiplicacao: Double = 2.0, bloco: suspend () -\u0026gt; T ): T { var delayAtual = delayInicial var ultimaExcecao: Exception? = null repeat(tentativas) { tentativa -\u0026gt; try { return bloco() } catch (e: Exception) { ultimaExcecao = e if (tentativa \u0026lt; tentativas - 1) { delay(delayAtual) delayAtual = (delayAtual * fatorMultiplicacao).toLong() } } } throw ultimaExcecao!! } Comunicação Assíncrona com Mensageria Para operações que não precisam de resposta imediata, use mensageria:\n// Produtor de mensagens (Pedidos Service) @Component class PedidoEventPublisher( private val rabbitTemplate: RabbitTemplate ) { fun publicarPedidoCriado(pedido: Pedido) { val evento = PedidoCriadoEvento( pedidoId = pedido.id, clienteId = pedido.clienteId, valorTotal = pedido.valorTotal, timestamp = Instant.now() ) rabbitTemplate.convertAndSend( \u0026#34;pedidos-exchange\u0026#34;, \u0026#34;pedido.criado\u0026#34;, evento ) } } // Consumidor de mensagens (Notificacoes Service) @Component class PedidoEventConsumer( private val notificacaoService: NotificacaoService ) { @RabbitListener(queues = [\u0026#34;notificacoes-queue\u0026#34;]) fun processarPedidoCriado(evento: PedidoCriadoEvento) { notificacaoService.enviarConfirmacaoPedido( clienteId = evento.clienteId, pedidoId = evento.pedidoId, valor = evento.valorTotal ) } } Circuit Breaker O padrão Circuit Breaker previne falhas em cascata quando um serviço esta indisponivel:\nclass CircuitBreaker( private val nome: String, private val limiteAberto: Int = 5, private val tempoRecuperacao: Long = 30_000L ) { private var falhas = AtomicInteger(0) private var estado = AtomicReference(Estado.FECHADO) private var ultimaFalha = AtomicLong(0) enum class Estado { FECHADO, ABERTO, MEIO_ABERTO } suspend fun \u0026lt;T\u0026gt; executar(bloco: suspend () -\u0026gt; T): T { when (estado.get()) { Estado.ABERTO -\u0026gt; { if (System.currentTimeMillis() - ultimaFalha.get() \u0026gt; tempoRecuperacao) { estado.set(Estado.MEIO_ABERTO) } else { throw CircuitBreakerAberto(\u0026#34;Circuit breaker $nome esta aberto\u0026#34;) } } else -\u0026gt; { /* continuar */ } } return try { val resultado = bloco() onSucesso() resultado } catch (e: Exception) { onFalha() throw e } } private fun onSucesso() { falhas.set(0) estado.set(Estado.FECHADO) } private fun onFalha() { val totalFalhas = falhas.incrementAndGet() ultimaFalha.set(System.currentTimeMillis()) if (totalFalhas \u0026gt;= limiteAberto) { estado.set(Estado.ABERTO) } } } Observabilidade Microsserviços exigem monitoramento robusto. Implemente logging estruturado, métricas e tracing:\n// Logging estruturado com contexto fun Application.configurarLogging() { install(CallLogging) { level = Level.INFO format { call -\u0026gt; val status = call.response.status() val metodo = call.request.httpMethod.value val uri = call.request.uri val duracao = call.processingTimeMillis() \u0026#34;$metodo $uri -\u0026gt; $status (${duracao}ms)\u0026#34; } } } // Endpoint de métricas fun Route.metricasRoutes(métricas: MetricasService) { get(\u0026#34;/metrics\u0026#34;) { call.respond(mapOf( \u0026#34;requisicoes_total\u0026#34; to métricas.totalRequisicoes(), \u0026#34;requisicoes_por_segundo\u0026#34; to métricas.requisicoesPorSegundo(), \u0026#34;latencia_media_ms\u0026#34; to métricas.latenciaMedia(), \u0026#34;erros_total\u0026#34; to métricas.totalErros(), \u0026#34;uptime_segundos\u0026#34; to métricas.uptime() )) } } Boas Práticas para Microsserviços com Kotlin Um banco por serviço: cada microservico deve ter seu próprio banco de dados. Nunca compartilhe bancos entre serviços. Contratos bem definidos: use DTOs versionados para comunicação. Nunca exponha entidades internas. Cache compartilhado com cautela: use Redis para cache, sessões ou rate limiting quando houver ganho claro, mas mantenha TTL, nomes de chaves e fallback documentados. Veja Kotlin com Redis para os padrões básicos. Comunicação assíncrona quando possível: use mensageria para operações que não exigem resposta imediata. Resiliência e obrigatória: implemente retry, circuit breaker e timeout em toda comunicação entre serviços. Health checks em todos os serviços: permita que orquestradores detectem e reiniciem serviços com problemas. Centralize logs e métricas: use ELK Stack, Grafana ou similar para visualizar o comportamento de todos os serviços. Idempotencia: endpoints de criação e atualização devem ser idempotentes para lidar com retries seguros. Erros Comuns e Armadilhas Microsserviços prematuros: dividir uma aplicação em microsserviços antes de entender os limites do dominio resulta em serviços mal definidos que precisam de refatoração constante. Acoplamento temporal: se o serviço A precisa esperar sincrona-mente pelo serviço B, que espera pelo C, você criou um monolito distribuído. Prefira comunicação assíncrona. Transacoes distribuidas: ACID transactions entre microsserviços são extremamente complexas. Use padrões como Saga para consistencia eventual. Ignorar falhas de rede: a rede falha. Sempre. Implemente timeout, retry e fallback em toda comunicação entre serviços. Falta de observabilidade: sem logs centralizados e tracing distribuído, debugar problemas em producao se torna quase impossivel. Over-engineering: não crie um microservico para cada entidade. Agrupe por capacidade de negócio. Conclusão e Próximos Passos Microsserviços com Kotlin oferecem uma arquitetura poderosa para sistemas que precisam escalar e evoluir independentemente. A combinacao de coroutines para comunicação assíncrona, frameworks leves como Ktor e o ecossistema robusto do Spring Boot cria uma base solida para sistemas distribuidos. Go é outra linguagem excelente para microsserviços, com binários estáticos e startup instantâneo, enquanto Rust oferece performance máxima com consumo mínimo de recursos. Para aprofundar, explore nossos guias sobre Docker para containerizacao, CI/CD para deploy automatizado e REST APIs para design de contratos entre serviços. Lembre-se: comece simples e evolua a arquitetura conforme a necessidade real do projeto.\n","permalink":"https://kotlin.dev.br/guias/guia-kotlin-microservicos/","summary":"\u003cp\u003eMicrosserviços representam uma abordagem arquitetural onde uma aplicação e dividida em serviços pequenos, independentes e especializados, cada um responsavel por uma capacidade de negócio específica. Kotlin se destaca nesse cenário gracas ao suporte nativo a coroutines para comunicação assíncrona, sintaxe concisa que reduz boilerplate e compatibilidade total com o ecossistema JVM. Neste guia, vamos projetar e implementar uma arquitetura de microsserviços com Kotlin, abordando comunicação entre serviços, resiliência, observabilidade e estrategias de deploy.\u003c/p\u003e","title":"Microsserviços com Kotlin: Guia Completo em Português | Kotlin Brasil"},{"content":"Um portfólio bem construído pode ser o diferencial entre receber uma proposta de emprego ou ser ignorado. Para desenvolvedores Kotlin, ter projetos que demonstram suas habilidades de forma clara e organizada é fundamental. Neste guia, vou te mostrar exatamente como montar um portfólio que se destaca.\nPor Que Portfólio Importa Mais Que Currículo No mundo de desenvolvimento, recrutadores e tech leads querem ver código. Um currículo diz o que você afirma saber. Um portfólio prova o que você realmente sabe fazer.\nEmpresas como Nubank, iFood e PicPay frequentemente pedem acesso ao GitHub do candidato antes mesmo de agendar uma entrevista. Ter projetos bem organizados lá pode abrir portas que um currículo sozinho não abre.\nEstrutura de um Portfólio Eficaz Um portfólio de desenvolvedor Kotlin deve ter entre 3 e 5 projetos de qualidade. Qualidade importa muito mais que quantidade. Um único projeto bem feito impressiona mais que dez projetos meia-boca.\nProjeto 1: App Android Completo Este é o projeto obrigatório para quem quer vagas Android. Deve demonstrar:\n// Arquitetura limpa com MVVM // domain/usecase/GetProductsUseCase.kt class GetProductsUseCase( private val repository: ProductRepository ) { operator fun invoke( category: String? = null, sortBy: SortOption = SortOption.NAME ): Flow\u0026lt;Result\u0026lt;List\u0026lt;Product\u0026gt;\u0026gt;\u0026gt; { return repository.getProducts() .map { result -\u0026gt; result.map { products -\u0026gt; products .let { list -\u0026gt; if (category != null) { list.filter { it.category == category } } else list } .sortedWith(sortBy.comparator) } } } } // presentation/viewmodel/ProductListViewModel.kt @HiltViewModel class ProductListViewModel @Inject constructor( private val getProducts: GetProductsUseCase, private val savedStateHandle: SavedStateHandle ) : ViewModel() { private val _uiState = MutableStateFlow(ProductListUiState()) val uiState: StateFlow\u0026lt;ProductListUiState\u0026gt; = _uiState.asStateFlow() private val selectedCategory = savedStateHandle.getStateFlow\u0026lt;String?\u0026gt;( \u0026#34;category\u0026#34;, null ) init { viewModelScope.launch { selectedCategory.flatMapLatest { category -\u0026gt; getProducts(category = category) }.collect { result -\u0026gt; result .onSuccess { products -\u0026gt; _uiState.update { it.copy(products = products, loading = false) } } .onFailure { error -\u0026gt; _uiState.update { it.copy(error = error.message, loading = false) } } } } } } O app deve consumir uma API pública (como PokeAPI, TMDB ou OpenWeather), ter persistência local, tratamento de erros e uma UI bem construída com Jetpack Compose.\nProjeto 2: API Backend com Kotlin Mostra que você vai além do mobile:\n// API REST com Spring Boot // Estrutura bem organizada @RestController @RequestMapping(\u0026#34;/api/v1/bookmarks\u0026#34;) class BookmarkController( private val bookmarkService: BookmarkService ) { @GetMapping suspend fun list( @AuthenticationPrincipal user: UserPrincipal, @RequestParam(defaultValue = \u0026#34;0\u0026#34;) page: Int, @RequestParam(defaultValue = \u0026#34;20\u0026#34;) size: Int ): ResponseEntity\u0026lt;PagedResponse\u0026lt;BookmarkDTO\u0026gt;\u0026gt; { val bookmarks = bookmarkService.listByUser(user.id, page, size) return ResponseEntity.ok(bookmarks) } @PostMapping suspend fun create( @AuthenticationPrincipal user: UserPrincipal, @Valid @RequestBody request: CreateBookmarkRequest ): ResponseEntity\u0026lt;BookmarkDTO\u0026gt; { val bookmark = bookmarkService.create(user.id, request) return ResponseEntity.status(HttpStatus.CREATED).body(bookmark) } @DeleteMapping(\u0026#34;/{id}\u0026#34;) suspend fun delete( @AuthenticationPrincipal user: UserPrincipal, @PathVariable id: String ): ResponseEntity\u0026lt;Unit\u0026gt; { bookmarkService.delete(user.id, id) return ResponseEntity.noContent().build() } } // Testes - Fundamental para impressionar @SpringBootTest @AutoConfigureMockMvc class BookmarkControllerTest { @Autowired private lateinit var mockMvc: MockMvc @MockkBean private lateinit var bookmarkService: BookmarkService @Test fun `should return paginated bookmarks`() { val bookmarks = listOf( createBookmarkDTO(id = \u0026#34;1\u0026#34;, title = \u0026#34;Kotlin Blog\u0026#34;), createBookmarkDTO(id = \u0026#34;2\u0026#34;, title = \u0026#34;Spring Docs\u0026#34;) ) coEvery { bookmarkService.listByUser(any(), any(), any()) } returns PagedResponse(bookmarks, total = 2, page = 0, size = 20) mockMvc.get(\u0026#34;/api/v1/bookmarks\u0026#34;) { header(\u0026#34;Authorization\u0026#34;, \u0026#34;Bearer ${generateTestToken()}\u0026#34;) }.andExpect { status { isOk() } jsonPath(\u0026#34;$.content\u0026#34;) { isArray() } jsonPath(\u0026#34;$.content.length()\u0026#34;) { value(2) } jsonPath(\u0026#34;$.total\u0026#34;) { value(2) } } } } Projeto 3: Biblioteca ou Ferramenta Criar uma biblioteca ou CLI mostra maturidade técnica:\n// Exemplo: DSL para validação // Mostra conhecimento avançado de Kotlin class ValidationBuilder\u0026lt;T\u0026gt; { private val rules = mutableListOf\u0026lt;ValidationRule\u0026lt;T\u0026gt;\u0026gt;() fun field( name: String, extractor: (T) -\u0026gt; Any?, block: FieldValidationBuilder.() -\u0026gt; Unit ) { val fieldBuilder = FieldValidationBuilder(name, extractor) fieldBuilder.block() rules.addAll(fieldBuilder.build()) } fun validate(obj: T): ValidationResult { val errors = rules.mapNotNull { rule -\u0026gt; rule.validate(obj) } return if (errors.isEmpty()) { ValidationResult.Valid } else { ValidationResult.Invalid(errors) } } } // Uso da DSL val userValidator = validator\u0026lt;User\u0026gt; { field(\u0026#34;nome\u0026#34;, { it.nome }) { notBlank() minLength(2) maxLength(100) } field(\u0026#34;email\u0026#34;, { it.email }) { notBlank() matchesPattern(EMAIL_REGEX) } field(\u0026#34;idade\u0026#34;, { it.idade }) { min(18) max(120) } } val resultado = userValidator.validate(user) when (resultado) { is ValidationResult.Valid -\u0026gt; salvarUsuario(user) is ValidationResult.Invalid -\u0026gt; mostrarErros(resultado.errors) } Qualidade do Código Recrutadores olham não apenas se o código funciona, mas como ele é escrito. Siga estas práticas:\nNomenclatura Clara // Ruim fun proc(d: List\u0026lt;Int\u0026gt;): Int = d.filter { it \u0026gt; 0 }.sum() // Bom fun calcularSomaPositivos(valores: List\u0026lt;Int\u0026gt;): Int { return valores .filter { it \u0026gt; 0 } .sum() } Commit Messages Significativas Seus commits contam uma historia. Em vez de \u0026ldquo;fix bug\u0026rdquo; ou \u0026ldquo;update code\u0026rdquo;, escreva:\n\u0026ldquo;Adiciona paginação na listagem de produtos\u0026rdquo; \u0026ldquo;Corrige tratamento de erro quando API retorna 404\u0026rdquo; \u0026ldquo;Refatora ViewModel para usar StateFlow em vez de LiveData\u0026rdquo; README Bem Escrito Cada projeto deve ter um README que explica:\nO que o projeto faz Tecnologias utilizadas Como rodar localmente Screenshots ou GIFs (para apps visuais) Decisões arquiteturais e por que foram tomadas Organização do GitHub Perfil Profissional Configure seu perfil do GitHub com:\nFoto profissional Bio clara mencionando Kotlin Link para LinkedIn Projetos pinados (os melhores no topo) Contribuições Regulares O gráfico de contribuições do GitHub mostra consistência. Tente:\nFazer commits regularmente (mesmo pequenos) Abrir issues e PRs em projetos open source Revisar código de outros Testes: O Diferencial A maioria dos portfólios não tem testes. Ter testes bem escritos é um diferencial enorme:\n// Testes de ViewModel com coroutines class ProductViewModelTest { @get:Rule val mainDispatcherRule = MainDispatcherRule() private val repository = FakeProductRepository() private lateinit var viewModel: ProductViewModel @Before fun setup() { viewModel = ProductViewModel(GetProductsUseCase(repository)) } @Test fun `loading state should be true initially`() = runTest { val states = mutableListOf\u0026lt;ProductListUiState\u0026gt;() val job = launch { viewModel.uiState.toList(states) } advanceUntilIdle() assertThat(states.first().loading).isTrue() assertThat(states.last().loading).isFalse() assertThat(states.last().products).isNotEmpty() job.cancel() } } Erros Comuns a Evitar Projetos incompletos: Melhor ter 3 projetos terminados do que 10 pela metade Código copiado de tutoriais: Recrutadores percebem. Adicione suas proprias features Sem tratamento de erros: Apps que crasham causam pessima impressao Sem .gitignore: Nunca commite arquivos de build, IDE ou credenciais Falta de documentação: Código sem README parece abandonado Cronograma Sugerido Se você está começando do zero, siga este cronograma:\nSemanas 1-3: Projeto Android completo Semanas 4-5: Projeto backend com API Semana 6: Projeto biblioteca/ferramenta Semana 7: Polimento, testes e documentação Semana 8: Revisão final e início das candidaturas Conclusão Montar um portfólio sólido requer dedicação, mas o retorno é enorme. Projetos bem feitos demonstram suas habilidades de forma que nenhum currículo consegue. Foque em qualidade, mantenha o código organizado, escreva testes e documente suas decisões. Para quem está começando, esse cuidado também influencia a faixa inicial de salário como desenvolvedor Kotlin júnior, especialmente em vagas Android e backend com mentoria.\nLembre-se: o portfólio é um documento vivo. Continue melhorando seus projetos, adicionando features e aprendendo novas tecnologias. Ter projetos em múltiplas linguagens como Go ou Python demonstra versatilidade e amplia suas oportunidades. Cada melhoria é um investimento na sua carreira como desenvolvedor Kotlin.\n","permalink":"https://kotlin.dev.br/blog/portfolio-desenvolvedor-kotlin/","summary":"\u003cp\u003eUm portfólio bem construído pode ser o diferencial entre receber uma proposta de emprego ou ser ignorado. Para desenvolvedores Kotlin, ter projetos que demonstram suas habilidades de forma clara e organizada é fundamental. Neste guia, vou te mostrar exatamente como montar um portfólio que se destaca.\u003c/p\u003e\n\u003ch2 id=\"por-que-portfólio-importa-mais-que-currículo\"\u003ePor Que Portfólio Importa Mais Que Currículo\u003c/h2\u003e\n\u003cp\u003eNo mundo de desenvolvimento, recrutadores e tech leads querem ver código. Um currículo diz o que você afirma saber. Um portfólio prova o que você realmente sabe fazer.\u003c/p\u003e","title":"Portfolio de Desenvolvedor Kotlin: Como Montar o Seu | Kotlin Brasil"},{"content":"Docker revolucionou a forma como empacotamos e distribuimos aplicações, e projetos Kotlin se beneficiam enormemente dessa tecnologia. Containerizar uma aplicação Kotlin garante que ela rode de forma identica em qualquer ambiente, eliminando o clássico problema do \u0026ldquo;funciona na minha maquina\u0026rdquo;. Neste guia, vamos desde a criação de Dockerfiles otimizados até orquestracao com Docker Compose, cobrindo aplicações Spring Boot, Ktor e scripts Kotlin puros. Você vai aprender a construir imagens leves, seguras e prontas para producao.\nPor Que Docker para Projetos Kotlin Aplicações Kotlin rodam na JVM, que precisa estar instalada e configurada corretamente no servidor. Docker encapsula a JVM, as dependências é a aplicação em um container isolado. As vantagens incluem ambiente consistente entre desenvolvimento e producao, facilidade de escalar horizontalmente, isolamento de processos e deploy simplificado.\nDockerfile Básico para Kotlin Vamos começar com um Dockerfile simples para uma aplicação Kotlin com Gradle:\n// Dockerfile FROM eclipse-temurin:17-jdk AS build WORKDIR /app # Copiar arquivos de configuracao do Gradle primeiro (para cache de dependências) COPY gradle gradle COPY gradlew . COPY build.gradle.kts . COPY settings.gradle.kts . COPY gradle.properties . # Baixar dependências (camada cacheada) RUN chmod +x gradlew \u0026amp;\u0026amp; ./gradlew dependencies --no-daemon # Copiar codigo fonte COPY src src # Compilar RUN ./gradlew build -x test --no-daemon # Imagem de runtime FROM eclipse-temurin:17-jre WORKDIR /app COPY --from=build /app/build/libs/*-all.jar app.jar EXPOSE 8080 ENTRYPOINT [\u0026#34;java\u0026#34;, \u0026#34;-jar\u0026#34;, \u0026#34;app.jar\u0026#34;] Multi-Stage Build Otimizado O multi-stage build separa o ambiente de compilação do runtime, resultando em imagens significativamente menores:\n// Dockerfile otimizado # Etapa 1: Cache de dependências FROM eclipse-temurin:17-jdk-alpine AS deps WORKDIR /app COPY gradle gradle COPY gradlew . COPY build.gradle.kts . COPY settings.gradle.kts . RUN chmod +x gradlew \u0026amp;\u0026amp; ./gradlew dependencies --no-daemon # Etapa 2: Build FROM eclipse-temurin:17-jdk-alpine AS build WORKDIR /app COPY --from=deps /root/.gradle /root/.gradle COPY . . RUN chmod +x gradlew \u0026amp;\u0026amp; ./gradlew shadowJar --no-daemon # Etapa 3: Runtime FROM eclipse-temurin:17-jre-alpine WORKDIR /app # Criar usuario nao-root RUN addgroup -S appgroup \u0026amp;\u0026amp; adduser -S appuser -G appgroup # Copiar apenas o JAR COPY --from=build /app/build/libs/*-all.jar app.jar # Configuração de segurança USER appuser # Configuração da JVM ENV JAVA_OPTS=\u0026#34;-XX:+UseContainerSupport \\ -XX:MaxRAMPercentage=75.0 \\ -XX:+UseG1GC \\ -Djava.security.egd=file:/dev/./urandom\u0026#34; EXPOSE 8080 HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \\ CMD wget -qO- http://localhost:8080/health || exit 1 ENTRYPOINT [\u0026#34;sh\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#34;java $JAVA_OPTS -jar app.jar\u0026#34;] A imagem final usa jre-alpine em vez de jdk, reduzindo o tamanho de centenas de MB para dezenas de MB.\nDockerfile para Spring Boot O Spring Boot oferece suporte nativo a build de imagens via Buildpacks, mas Dockerfiles manuais oferecem mais controle:\n// Dockerfile para Spring Boot com layers FROM eclipse-temurin:17-jdk-alpine AS build WORKDIR /app COPY . . RUN chmod +x gradlew \u0026amp;\u0026amp; ./gradlew bootJar --no-daemon # Extrair layers do Spring Boot FROM eclipse-temurin:17-jdk-alpine AS layers WORKDIR /app COPY --from=build /app/build/libs/*.jar app.jar RUN java -Djarmode=layertools -jar app.jar extract # Runtime com layers separadas (melhor cache do Docker) FROM eclipse-temurin:17-jre-alpine WORKDIR /app RUN addgroup -S spring \u0026amp;\u0026amp; adduser -S spring -G spring USER spring COPY --from=layers /app/dependencies/ ./ COPY --from=layers /app/spring-boot-loader/ ./ COPY --from=layers /app/snapshot-dependencies/ ./ COPY --from=layers /app/application/ ./ EXPOSE 8080 ENTRYPOINT [\u0026#34;java\u0026#34;, \u0026#34;org.springframework.boot.loader.launch.JarLauncher\u0026#34;] As layers do Spring Boot permitem que o Docker reutilize cache para dependências que não mudaram, acelerando builds subsequentes.\nDockerfile para Ktor // Dockerfile para Ktor FROM eclipse-temurin:17-jdk-alpine AS build WORKDIR /app COPY . . RUN chmod +x gradlew \u0026amp;\u0026amp; ./gradlew buildFatJar --no-daemon FROM eclipse-temurin:17-jre-alpine WORKDIR /app RUN addgroup -S ktor \u0026amp;\u0026amp; adduser -S ktor -G ktor USER ktor COPY --from=build /app/build/libs/*-all.jar app.jar ENV JAVA_OPTS=\u0026#34;-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0\u0026#34; EXPOSE 8080 ENTRYPOINT [\u0026#34;sh\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#34;java $JAVA_OPTS -jar app.jar\u0026#34;] Docker Compose para Desenvolvimento O Docker Compose orquestra múltiplos containers para desenvolvimento local:\n// docker-compose.yml version: \u0026#39;3.8\u0026#39; services: app: build: context: . dockerfile: Dockerfile ports: - \u0026#34;8080:8080\u0026#34; environment: - DATABASE_URL=jdbc:postgresql://postgres:5432/meuapp - DATABASE_USER=appuser - DATABASE_PASSWORD=apppass - REDIS_HOST=redis - REDIS_PORT=6379 depends_on: postgres: condition: service_healthy redis: condition: service_started networks: - app-network postgres: image: postgres:16-alpine environment: POSTGRES_DB: meuapp POSTGRES_USER: appuser POSTGRES_PASSWORD: apppass ports: - \u0026#34;5432:5432\u0026#34; volumes: - postgres-data:/var/lib/postgresql/data - ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql healthcheck: test: [\u0026#34;CMD-SHELL\u0026#34;, \u0026#34;pg_isready -U appuser -d meuapp\u0026#34;] interval: 5s timeout: 3s retries: 5 networks: - app-network redis: image: redis:7-alpine ports: - \u0026#34;6379:6379\u0026#34; volumes: - redis-data:/data networks: - app-network pgadmin: image: dpage/pgadmin4 environment: PGADMIN_DEFAULT_EMAIL: admin@local.dev PGADMIN_DEFAULT_PASSWORD: admin ports: - \u0026#34;5050:80\u0026#34; depends_on: - postgres networks: - app-network volumes: postgres-data: redis-data: networks: app-network: driver: bridge Docker Compose para Testes de Integração Crie um compose separado para testes:\n// docker-compose.test.yml version: \u0026#39;3.8\u0026#39; services: test-db: image: postgres:16-alpine environment: POSTGRES_DB: testdb POSTGRES_USER: testuser POSTGRES_PASSWORD: testpass ports: - \u0026#34;5433:5432\u0026#34; tmpfs: - /var/lib/postgresql/data # Mais rapido para testes No Gradle, crie uma task que gerencia o ciclo de vida dos containers de teste:\n// build.gradle.kts tasks.register\u0026lt;Exec\u0026gt;(\u0026#34;startTestContainers\u0026#34;) { commandLine(\u0026#34;docker-compose\u0026#34;, \u0026#34;-f\u0026#34;, \u0026#34;docker-compose.test.yml\u0026#34;, \u0026#34;up\u0026#34;, \u0026#34;-d\u0026#34;) } tasks.register\u0026lt;Exec\u0026gt;(\u0026#34;stopTestContainers\u0026#34;) { commandLine(\u0026#34;docker-compose\u0026#34;, \u0026#34;-f\u0026#34;, \u0026#34;docker-compose.test.yml\u0026#34;, \u0026#34;down\u0026#34;) } Configuração da JVM para Containers A JVM precisa de configurações específicas para funcionar bem em containers:\n// application.conf (Ktor) ou application.yml (Spring) // A JVM deve respeitar os limites de memoria do container // Flags importantes: // -XX:+UseContainerSupport -\u0026gt; JVM respeita cgroups // -XX:MaxRAMPercentage=75.0 -\u0026gt; Usa 75% da RAM do container // -XX:+UseG1GC -\u0026gt; GC recomendado para containers // -XX:+ExitOnOutOfMemoryError -\u0026gt; Reinicia o container em OOM No Kotlin, configure o health check endpoint:\n// Health check para Docker fun Application.configurarHealthCheck() { routing { get(\u0026#34;/health\u0026#34;) { // Verificar dependências val dbOk = verificarBancoDeDados() val redisOk = verificarRedis() if (dbOk \u0026amp;\u0026amp; redisOk) { call.respond(HttpStatusCode.OK, mapOf( \u0026#34;status\u0026#34; to \u0026#34;UP\u0026#34;, \u0026#34;database\u0026#34; to \u0026#34;OK\u0026#34;, \u0026#34;redis\u0026#34; to \u0026#34;OK\u0026#34; )) } else { call.respond(HttpStatusCode.ServiceUnavailable, mapOf( \u0026#34;status\u0026#34; to \u0026#34;DOWN\u0026#34;, \u0026#34;database\u0026#34; to if (dbOk) \u0026#34;OK\u0026#34; else \u0026#34;FAIL\u0026#34;, \u0026#34;redis\u0026#34; to if (redisOk) \u0026#34;OK\u0026#34; else \u0026#34;FAIL\u0026#34; )) } } } } Boas Práticas para Kotlin com Docker Use multi-stage builds: separe compilação de runtime para imagens menores e mais seguras. Imagens Alpine: prefira imagens baseadas em Alpine Linux para reduzir tamanho. Usuario não-root: nunca rode a aplicação como root no container. Ordene COPY para cache: copie arquivos que mudam menos (gradle, build configs) antes do código fonte. Use .dockerignore: exclua .git, build/, .gradle/, *.md e outros arquivos desnecessários. Configure health checks: permita que orquestradores detectem e reiniciem containers com problemas. Limite recursos: defina limites de CPU e memória no Docker Compose ou Kubernetes. Use variaveis de ambiente para configuração: nunca hardcode URLs, credenciais ou parametros de ambiente na imagem. Erros Comuns e Armadilhas Imagem grande demais: usar jdk em vez de jre no runtime ou não usar Alpine dobra ou triplica o tamanho da imagem. Cache de build não aproveitado: copiar todo o projeto antes de baixar dependências invalida o cache a cada mudanca de código. JVM ignorando limites do container: sem -XX:+UseContainerSupport, a JVM pode alocar mais memória do que o container permite, causando OOM killer. Rodar como root: vulnerabilidades na aplicação podem comprometer o host se o container roda como root. Secrets em variaveis de ambiente visíveis: use Docker secrets ou ferramentas como HashiCorp Vault para credenciais sensiveis. Nao configurar graceful shutdown: a aplicação deve responder ao sinal SIGTERM para encerrar conexoes e processos pendentes antes de parar. Conclusão e Próximos Passos Docker e uma ferramenta indispensavel para projetos Kotlin modernos, desde desenvolvimento local até deploy em producao. Com multi-stage builds, configuração adequada da JVM e Docker Compose, você tem um ambiente reproduzível e eficiente. Para ir além, explore Kubernetes para orquestracao de containers em escala, consulte nosso guia de CI/CD para integrar Docker ao pipeline de deploy e estude microsserviços para arquiteturas distribuídas containerizadas. Docker e Kubernetes são escritos em Go, e Rust produz imagens Docker extremamente pequenas (sem runtime) — vale conhecer ambas para entender o ecossistema de containers.\n","permalink":"https://kotlin.dev.br/guias/guia-kotlin-docker/","summary":"\u003cp\u003eDocker revolucionou a forma como empacotamos e distribuimos aplicações, e projetos Kotlin se beneficiam enormemente dessa tecnologia. Containerizar uma aplicação Kotlin garante que ela rode de forma identica em qualquer ambiente, eliminando o clássico problema do \u0026ldquo;funciona na minha maquina\u0026rdquo;. Neste guia, vamos desde a criação de Dockerfiles otimizados até orquestracao com Docker Compose, cobrindo aplicações Spring Boot, Ktor e scripts Kotlin puros. Você vai aprender a construir imagens leves, seguras e prontas para producao.\u003c/p\u003e","title":"Kotlin com Docker: Guia Completo em Português | Kotlin Brasil"},{"content":"Kotlin Multiplatform (KMP) permite compartilhar lógica de negócio entre Android, iOS, desktop e web usando uma única base de código Kotlin. Neste tutorial, vamos configurar um projeto KMP do zero, entender o mecanismo expect/actual, criar um módulo compartilhado, integrar com Compose Multiplatform para UI, usar Ktor Client para requisições HTTP e configurar injeção de dependências com Koin.\nO que é Kotlin Multiplatform? Diferente de soluções como Flutter ou React Native que substituem completamente a UI nativa, o KMP foca em compartilhar a lógica de negócio — modelos de dados, networking, válidações, regras de negócio — enquanto permite que cada plataforma use sua própria tecnologia de interface. Com a chegada do Compose Multiplatform, agora também é possível compartilhar a camada de UI entre Android, iOS e desktop.\nO KMP é uma tecnologia estável da JetBrains, já usada em produção por empresas como Netflix, Philips, VMWare e Cash App. A ideia central é simples: escreva código Kotlin no módulo commonMain e ele compila para JVM (Android), nativo (iOS via Kotlin/Native) e JavaScript (web).\nPasso 1: Configuração do Projeto A forma mais prática de criar um projeto KMP é usando o wizard em kmp.jetbrains.com. Para entender a fundo, vamos ver a configuração manual. A estrutura de diretórios fica assim:\nmeu-projeto-kmp/ ├── shared/ │ └── src/ │ ├── commonMain/kotlin/ # Código compartilhado │ ├── commonTest/kotlin/ # Testes compartilhados │ ├── androidMain/kotlin/ # Código Android-especifico │ └── iosMain/kotlin/ # Código iOS-especifico ├── androidApp/ # Aplicação Android ├── iosApp/ # Aplicação iOS (Xcode) └── build.gradle.kts O build.gradle.kts do módulo compartilhado:\n// shared/build.gradle.kts plugins { kotlin(\u0026#34;multiplatform\u0026#34;) id(\u0026#34;com.android.library\u0026#34;) kotlin(\u0026#34;plugin.serialization\u0026#34;) } kotlin { androidTarget { compilations.all { compileTaskProvider.configure { compilerOptions { jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) } } } } listOf( iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { it.binaries.framework { baseName = \u0026#34;shared\u0026#34; } } sourceSets { commonMain.dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1\u0026#34;) implementation(\u0026#34;io.ktor:ktor-client-core:2.3.12\u0026#34;) implementation(\u0026#34;io.ktor:ktor-client-content-negotiation:2.3.12\u0026#34;) implementation(\u0026#34;io.ktor:ktor-serialization-kotlinx-json:2.3.12\u0026#34;) implementation(\u0026#34;io.insert-koin:koin-core:3.5.6\u0026#34;) } androidMain.dependencies { implementation(\u0026#34;io.ktor:ktor-client-okhttp:2.3.12\u0026#34;) } iosMain.dependencies { implementation(\u0026#34;io.ktor:ktor-client-darwin:2.3.12\u0026#34;) } } } android { namespace = \u0026#34;com.exemplo.shared\u0026#34; compileSdk = 34 defaultConfig { minSdk = 24 } } Note como as dependências são organizadas por source set: commonMain para código compartilhado, androidMain e iosMain para implementações específicas de plataforma. O Ktor Client, por exemplo, usa OkHttp no Android e Darwin no iOS.\nPasso 2: Mecanismo expect/actual O expect/actual é o recurso que permite declarar uma API no código comum e fornecer implementações específicas por plataforma. Pense como uma interface resolvida em tempo de compilação.\n// commonMain/kotlin/Platform.kt expect class Platform() { val nome: String val versao: String } expect fun obterTimestampAtual(): Long // androidMain/kotlin/Platform.android.kt actual class Platform actual constructor() { actual val nome: String = \u0026#34;Android ${android.os.Build.VERSION.SDK_INT}\u0026#34; actual val versao: String = android.os.Build.VERSION.RELEASE } actual fun obterTimestampAtual(): Long = System.currentTimeMillis() // iosMain/kotlin/Platform.ios.kt import platform.UIKit.UIDevice import platform.Foundation.NSDate import platform.Foundation.timeIntervalSince1970 actual class Platform actual constructor() { actual val nome: String = UIDevice.currentDevice.systemName() actual val versao: String = UIDevice.currentDevice.systemVersion } actual fun obterTimestampAtual(): Long = (NSDate().timeIntervalSince1970 * 1000).toLong() No código comum, use Platform() normalmente — o compilador escolhe a implementação correta para cada target. O ideal é minimizar o uso de expect/actual e mover a maior parte da lógica para commonMain, usando-o apenas quando realmente precisa de APIs nativas.\nPasso 3: Módulo Compartilhado com Lógica de Negócio Vamos criar um módulo compartilhado que busca dados de uma API e aplica regras de negócio:\n// commonMain/kotlin/modelo/Produto.kt import kotlinx.serialization.Serializable @Serializable data class Produto( val id: Int, val nome: String, val preco: Double, val categoria: String ) @Serializable data class RespostaApi\u0026lt;T\u0026gt;( val dados: List\u0026lt;T\u0026gt;, val total: Int ) // commonMain/kotlin/repositorio/ProdutoRepositorio.kt import io.ktor.client.* import io.ktor.client.call.* import io.ktor.client.request.* class ProdutoRepositorio(private val client: HttpClient) { suspend fun buscarProdutos(): List\u0026lt;Produto\u0026gt; { val resposta: RespostaApi\u0026lt;Produto\u0026gt; = client.get(\u0026#34;https://api.exemplo.com/produtos\u0026#34;).body() return resposta.dados } suspend fun buscarPorCategoria(categoria: String): List\u0026lt;Produto\u0026gt; { return buscarProdutos().filter { it.categoria == categoria } } } // commonMain/kotlin/usecase/ListarProdutosUseCase.kt class ListarProdutosUseCase(private val repositorio: ProdutoRepositorio) { suspend fun executar(filtroPrecoMaximo: Double? = null): List\u0026lt;Produto\u0026gt; { val produtos = repositorio.buscarProdutos() return if (filtroPrecoMaximo != null) { produtos.filter { it.preco \u0026lt;= filtroPrecoMaximo } .sortedBy { it.preco } } else { produtos.sortedBy { it.nome } } } } Toda essa lógica compila para Android, iOS e qualquer outro target. As data classes com @Serializable funcionam em todas as plataformas graças ao kotlinx.serialization, que gera código de serialização em tempo de compilação.\nPasso 4: Compose Multiplatform para UI Compartilhada Com o Compose Multiplatform, você pode compartilhar também a camada de UI entre Android, iOS e desktop usando a mesma API do Jetpack Compose:\n// commonMain/kotlin/ui/TelaProdutos.kt import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @Composable fun TelaProdutos(viewModel: ProdutosViewModel) { val estado by viewModel.estado.collectAsState() LaunchedEffect(Unit) { viewModel.carregarProdutos() } Column(modifier = Modifier.fillMaxSize().padding(16.dp)) { Text( text = \u0026#34;Produtos\u0026#34;, style = MaterialTheme.typography.headlineMedium ) Spacer(modifier = Modifier.height(16.dp)) when { estado.carregando -\u0026gt; CircularProgressIndicator() estado.erro != null -\u0026gt; Text(\u0026#34;Erro: ${estado.erro}\u0026#34;, color = MaterialTheme.colorScheme.error) else -\u0026gt; LazyColumn { items(estado.produtos) { produto -\u0026gt; CartaoProduto(produto) } } } } } @Composable fun CartaoProduto(produto: Produto) { Card( modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp) ) { Column(modifier = Modifier.padding(16.dp)) { Text(text = produto.nome, style = MaterialTheme.typography.titleMedium) Text(text = \u0026#34;R$ ${\u0026#34;%.2f\u0026#34;.format(produto.preco)}\u0026#34;) Text(text = produto.categoria, style = MaterialTheme.typography.bodySmall) } } } O Compose Multiplatform usa exatamente a mesma API do Jetpack Compose do Android. O compilador gera renderização nativa para cada plataforma — Skia para iOS e desktop, Android Canvas para Android.\nPasso 5: Ktor Client Multiplatform A configuração do Ktor Client no código comum com engines específicas por plataforma:\n// commonMain/kotlin/rede/HttpClientFactory.kt import io.ktor.client.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.json.Json expect fun criarHttpClient(): HttpClient fun criarHttpClientComum(engine: HttpClientEngine): HttpClient { return HttpClient(engine) { install(ContentNegotiation) { json(Json { prettyPrint = true isLenient = true ignoreUnknownKeys = true }) } } } // androidMain/kotlin/rede/HttpClientFactory.android.kt import io.ktor.client.engine.okhttp.* actual fun criarHttpClient(): HttpClient = criarHttpClientComum(OkHttp.create()) // iosMain/kotlin/rede/HttpClientFactory.ios.kt import io.ktor.client.engine.darwin.* actual fun criarHttpClient(): HttpClient = criarHttpClientComum(Darwin.create()) Passo 6: Injeção de Dependências com Koin O Koin é um framework de DI leve que funciona nativamente com KMP, sem geração de código nem reflection pesada:\n// commonMain/kotlin/di/Modulos.kt import org.koin.core.module.dsl.singleOf import org.koin.dsl.module val moduloCompartilhado = module { single { criarHttpClient() } singleOf(::ProdutoRepositorio) singleOf(::ListarProdutosUseCase) factory { ProdutosViewModel(get()) } } // androidMain: inicializacao no Application class MeuApp : Application() { override fun onCreate() { super.onCreate() startKoin { androidContext(this@MeuApp) modules(moduloCompartilhado) } } } // iosMain: inicializacao para Swift fun inicializarKoin() { startKoin { modules(moduloCompartilhado) } } No lado iOS (Swift), chame IosMainKt.inicializarKoin() no AppDelegate. O Koin gerencia o grafo de dependências de forma idêntica em ambas as plataformas.\nErros Comuns 1. Usar APIs específicas de plataforma no commonMain: O código em commonMain só pode usar a biblioteca padrão do Kotlin e dependências multiplatform. Se precisar de java.io.File, use expect/actual ou a biblioteca okio que é multiplatform.\n2. Esquecer de adicionar todos os targets iOS: Sempre inclua iosX64() (simulador Intel), iosArm64() (dispositivo real) e iosSimulatorArm64() (simulador Apple Silicon). Omitir qualquer um causa erros confusos ao compilar.\n3. Serialização não funciona: O kotlinx.serialization exige o plugin de compilador kotlin(\u0026quot;plugin.serialization\u0026quot;). Sem ele, a annotation @Serializable não gera o serializer e você recebe erros em runtime.\n4. Coroutines no iOS congelando: No Kotlin/Native, o modelo de memória antigo tinha restrições com coroutines. Use Kotlin 1.9+ que traz o novo modelo de memória por padrão, eliminando esse problema.\n5. Dependências com versões incompatíveis: No KMP, todas as dependências devem suportar seus targets. Verifique no repositório da biblioteca se ela publica artefatos para iosArm64, iosX64, etc. Use o Kotlin Multiplatform Compatibility Guide como referência.\nConclusão e Próximos Passos Neste tutorial, construímos um projeto Kotlin Multiplatform completo com módulo compartilhado, mecanismo expect/actual, UI com Compose Multiplatform, networking com Ktor Client e DI com Koin. O KMP representa o futuro do desenvolvimento multiplataforma, permitindo reaproveitar lógica crítica sem sacrificar a experiência nativa de cada plataforma.\nComo próximos passos, explore SQLDelight para persistência local multiplatform, Napier para logging multiplataforma, e SKIE para melhorar a interoperabilidade Swift-Kotlin. Para transformar esse conhecimento em plano profissional, leia também o guia de desenvolvedor Kotlin Multiplatform. Para aprofundar seus conhecimentos em coroutines compartilhadas, confira nosso tutorial sobre Coroutines Avançadas e o guia Kotlin para Backend onde exploramos o Ktor em mais detalhes.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-multiplatform-tutorial/","summary":"\u003cp\u003e\u003cstrong\u003eKotlin Multiplatform\u003c/strong\u003e (KMP) permite compartilhar lógica de negócio entre Android, iOS, desktop e web usando uma única base de código Kotlin. Neste tutorial, vamos configurar um projeto KMP do zero, entender o mecanismo \u003ccode\u003eexpect\u003c/code\u003e/\u003ccode\u003eactual\u003c/code\u003e, criar um módulo compartilhado, integrar com Compose Multiplatform para UI, usar Ktor Client para requisições HTTP e configurar injeção de dependências com Koin.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-kotlin-multiplatform\"\u003eO que é Kotlin Multiplatform?\u003c/h2\u003e\n\u003cp\u003eDiferente de soluções como Flutter ou React Native que substituem completamente a UI nativa, o KMP foca em compartilhar a \u003cstrong\u003elógica de negócio\u003c/strong\u003e — modelos de dados, networking, válidações, regras de negócio — enquanto permite que cada plataforma use sua própria tecnologia de interface. Com a chegada do Compose Multiplatform, agora também é possível compartilhar a camada de UI entre Android, iOS e desktop.\u003c/p\u003e","title":"Kotlin Multiplatform Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"CI/CD é o conjunto de práticas que transforma um projeto Kotlin em software entregue com previsibilidade: cada mudança compila, roda testes, passa por análise de qualidade, gera artefatos e chega ao ambiente certo sem depender de uma sequência manual frágil. Em Kotlin, isso vale para Android, backend com Ktor ou Spring Boot, bibliotecas multiplataforma, CLIs e serviços que rodam em Docker ou Kubernetes.\nEste guia foi atualizado para 2026 com um foco prático: montar pipelines úteis em GitHub Actions e GitLab CI, configurar Gradle para ambientes de integração contínua, encaixar testes, detekt, ktlint, cache, Docker e deploy sem transformar o pipeline em um labirinto. Se você ainda está escolhendo a stack do projeto, leia também o guia de Kotlin para backend, o artigo de Kotlin com Spring Boot e o material de detekt e ktlint em Kotlin.\nO que um pipeline Kotlin precisa fazer Um pipeline Kotlin saudável costuma ter sete etapas:\nPreparar o ambiente com JDK, Gradle Wrapper e cache. Compilar o projeto para detectar erros rápidos. Executar testes unitários com JUnit, Kotest ou outra stack. Executar testes de integração quando houver banco, fila, API externa ou container. Verificar qualidade com detekt, ktlint e, quando fizer sentido, análise de cobertura. Gerar artefatos: JAR, imagem Docker, APK, AAB ou pacote multiplataforma. Publicar ou fazer deploy apenas quando as etapas anteriores passarem. O princípio é simples: falhar cedo, explicar bem a falha e evitar que código ruim chegue ao branch principal. O pipeline não precisa ser perfeito no primeiro dia. Ele precisa ser confiável o bastante para o time confiar nele.\nGitHub Actions para projetos Kotlin O GitHub Actions é uma boa escolha para projetos hospedados no GitHub e funciona muito bem com Gradle. Um pipeline inicial pode compilar, testar, rodar detekt e ktlint em pull requests e pushes para main.\n# .github/workflows/ci.yml name: Kotlin CI on: push: branches: [main] pull_request: branches: [main] concurrency: group: kotlin-ci-${{ github.ref }} cancel-in-progress: true env: GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.jvmargs=-Xmx2g jobs: build-test-quality: runs-on: ubuntu-latest services: postgres: image: postgres:16 env: POSTGRES_DB: app_test POSTGRES_USER: app POSTGRES_PASSWORD: app ports: - 5432:5432 options: \u0026gt;- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v4 - name: Configurar JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: \u0026#39;21\u0026#39; - name: Configurar Gradle uses: gradle/actions/setup-gradle@v4 - name: Permitir Gradle Wrapper run: chmod +x ./gradlew - name: Compilar run: ./gradlew assemble - name: Testes unitários run: ./gradlew test - name: Testes de integração run: ./gradlew integrationTest env: DATABASE_URL: jdbc:postgresql://localhost:5432/app_test DATABASE_USER: app DATABASE_PASSWORD: app - name: Qualidade de código run: ./gradlew ktlintCheck detekt - name: Publicar relatórios de teste if: always() uses: actions/upload-artifact@v4 with: name: test-reports path: | **/build/reports/tests/ **/build/test-results/ **/build/reports/detekt/ Para Android, a estrutura é parecida, mas você normalmente usa JDK 17 ou 21, configura o Android Gradle Plugin e roda tarefas como ./gradlew testDebugUnitTest, ./gradlew lintDebug e, em pipelines mais completos, testes instrumentados em emulador. Para bibliotecas Kotlin Multiplatform, separe jobs por alvo: JVM em Linux, iOS em macOS e JS/Wasm quando aplicável.\nDeploy com GitHub Actions O deploy não deve acontecer em qualquer push. Uma regra comum é publicar apenas quando uma tag v* é criada ou quando o branch main passa por revisão.\n# .github/workflows/deploy.yml name: Deploy on: push: tags: - \u0026#39;v*\u0026#39; jobs: docker-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: temurin java-version: \u0026#39;21\u0026#39; - uses: gradle/actions/setup-gradle@v4 - name: Build do JAR run: ./gradlew clean build - name: Login no registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build e push da imagem uses: docker/build-push-action@v6 with: context: . push: true tags: ghcr.io/sua-org/seu-app:${{ github.ref_name }} Se o destino for Kubernetes, a etapa seguinte pode atualizar um manifesto, acionar Argo CD, chamar um webhook interno ou aplicar um chart Helm. Para entender melhor esse caminho, veja também Kotlin com Kubernetes.\nGitLab CI para Kotlin GitLab CI é forte quando o repositório, o registry, os ambientes e as regras de deploy vivem dentro do GitLab. Para Kotlin, a diferença principal é a sintaxe do .gitlab-ci.yml, mas a lógica do pipeline continua a mesma.\n# .gitlab-ci.yml stages: - build - test - quality - package - deploy variables: GRADLE_OPTS: \u0026#34;-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs=-Xmx2g\u0026#34; GRADLE_USER_HOME: \u0026#34;$CI_PROJECT_DIR/.gradle\u0026#34; cache: key: \u0026#34;$CI_COMMIT_REF_SLUG\u0026#34; paths: - .gradle/wrapper - .gradle/caches build: stage: build image: eclipse-temurin:21-jdk script: - chmod +x ./gradlew - ./gradlew assemble artifacts: paths: - build/libs/*.jar expire_in: 1 week unit-tests: stage: test image: eclipse-temurin:21-jdk script: - ./gradlew test artifacts: when: always reports: junit: build/test-results/test/*.xml paths: - build/reports/tests/ integration-tests: stage: test image: eclipse-temurin:21-jdk services: - name: postgres:16 alias: postgres variables: POSTGRES_DB: app_test POSTGRES_USER: app POSTGRES_PASSWORD: app DATABASE_URL: jdbc:postgresql://postgres:5432/app_test script: - ./gradlew integrationTest quality: stage: quality image: eclipse-temurin:21-jdk script: - ./gradlew ktlintCheck detekt artifacts: when: always paths: - build/reports/detekt/ - build/reports/ktlint/ docker-build: stage: package image: docker:27 services: - docker:27-dind script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA rules: - if: \u0026#39;$CI_COMMIT_BRANCH == \u0026#34;main\u0026#34;\u0026#39; deploy-production: stage: deploy image: alpine:3.20 script: - echo \u0026#34;Acione aqui Helm, Argo CD, SSH ou API interna de deploy\u0026#34; rules: - if: \u0026#39;$CI_COMMIT_TAG\u0026#39; when: manual GitHub Actions ou GitLab CI: qual escolher para Kotlin? Para a consulta \u0026ldquo;GitLab CI vs Kotlin\u0026rdquo;, a resposta correta é que não existe uma disputa entre a ferramenta de CI e a linguagem. GitLab CI e GitHub Actions são orquestradores de pipeline; Kotlin é o projeto que será compilado, testado e entregue por eles. A decisão real é entre GitLab CI para um repositório Kotlin e GitHub Actions para um repositório Kotlin.\nEscolha GitHub Actions quando:\no código já está no GitHub; você quer marketplace grande de actions prontas; o time usa pull requests e branch protection do GitHub; o deploy é feito para GitHub Packages, GHCR, cloud providers ou serviços externos. Escolha GitLab CI quando:\no código está no GitLab; você quer registry, environments, approvals e runners no mesmo produto; o time precisa de pipelines complexos com regras internas; a empresa já opera GitLab Runner próprio. Para Kotlin em si, ambos resolvem. O ponto crítico é manter o Gradle Wrapper versionado, cachear dependências, separar testes rápidos de testes lentos e rodar qualidade de código antes do deploy. Se você quer exemplos focados no GitHub, veja Kotlin com GitHub Actions.\nConfiguração do Gradle para CI O build.gradle.kts deve facilitar o trabalho do pipeline. Não dependa de tarefas locais misteriosas ou scripts que só funcionam na máquina de uma pessoa.\ntasks.test { useJUnitPlatform() reports { junitXml.required.set(true) html.required.set(true) } maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1) } val integrationTest by tasks.registering(Test::class) { description = \u0026#34;Executa testes de integração\u0026#34; group = \u0026#34;verification\u0026#34; testClassesDirs = sourceSets[\u0026#34;integrationTest\u0026#34;].output.classesDirs classpath = sourceSets[\u0026#34;integrationTest\u0026#34;].runtimeClasspath useJUnitPlatform() shouldRunAfter(tasks.test) } Também vale padronizar versões com version catalog, travar a versão do JDK e evitar latest em imagens Docker. Builds reproduzíveis são mais fáceis de depurar e mais seguros para deploy.\ndetekt e ktlint no pipeline Qualidade de código não deve depender de revisão manual. detekt encontra complexidade, problemas de estilo e padrões perigosos; ktlint padroniza formatação. Uma configuração inicial pode ser simples:\nplugins { id(\u0026#34;io.gitlab.arturbosch.detekt\u0026#34;) version \u0026#34;1.23.8\u0026#34; id(\u0026#34;org.jlleitschuh.gradle.ktlint\u0026#34;) version \u0026#34;12.1.1\u0026#34; } detekt { buildUponDefaultConfig = true allRules = false config.setFrom(\u0026#34;$rootDir/config/detekt/detekt.yml\u0026#34;) } ktlint { android.set(false) outputToConsole.set(true) } Em times grandes, evite bloquear tudo no primeiro dia. Crie um baseline, rode as ferramentas no pipeline e vá reduzindo violações por módulo. O artigo Detekt e ktlint em Kotlin: qualidade de código em 2026 mostra esse rollout em mais detalhes.\nSecrets, variáveis e segurança Nunca coloque credenciais no repositório. Use secrets do GitHub, variáveis protegidas do GitLab, vault interno ou secret manager da sua nuvem. No código Kotlin, leia valores do ambiente e mantenha defaults apenas para desenvolvimento local.\nval databaseUrl = System.getenv(\u0026#34;DATABASE_URL\u0026#34;) ?: \u0026#34;jdbc:postgresql://localhost:5432/devdb\u0026#34; val databaseUser = System.getenv(\u0026#34;DATABASE_USER\u0026#34;) ?: \u0026#34;devuser\u0026#34; val databasePassword = System.getenv(\u0026#34;DATABASE_PASSWORD\u0026#34;) ?: \u0026#34;devpass\u0026#34; Também cuide dos logs. Um pipeline pode vazar tokens quando imprime comandos com variáveis, executa scripts com set -x ou mostra payloads de deploy. Secrets devem ser mascarados e acessíveis apenas nos jobs que realmente precisam deles.\nBoas práticas de CI/CD para Kotlin Fail fast: rode compilação e testes unitários antes de etapas caras. Cache de Gradle: reduza tempo de build sem esconder problemas de dependência. Gradle Wrapper versionado: não dependa do Gradle instalado no runner. JDK fixo: use uma versão explícita, como 17 ou 21, alinhada ao projeto. Relatórios sempre publicados: quando falhar, o time precisa ver o motivo. Separação por ambiente: staging, homologação e produção têm regras diferentes. Deploy manual onde existe risco: produção pode exigir aprovação, tag ou janela. Observabilidade: publique versão, commit e ambiente para facilitar rollback. Qualidade incremental: detekt e ktlint funcionam melhor quando viram hábito, não punição. Erros comuns O erro mais frequente é começar pelo deploy e esquecer a base: testes instáveis, cache mal configurado, secrets expostos e tarefas lentas demais. Outro problema é tratar CI/CD como arquivo esquecido: o pipeline precisa evoluir junto com o projeto. Se o projeto ganhou banco, fila ou cache, o pipeline precisa testar esse caminho. Se o projeto virou monólito modular, talvez seja hora de paralelizar módulos.\nTambém evite transformar o pipeline em uma cerimônia impossível de manter. Um bom pipeline Kotlin é explícito, rápido o suficiente para rodar em pull requests e rígido o suficiente para proteger main.\nFAQ rápido Preciso de GitHub Actions para usar Kotlin? Não. Você pode usar GitHub Actions, GitLab CI, Jenkins, Buildkite, CircleCI ou qualquer runner que tenha JDK e consiga executar o Gradle Wrapper.\nGitLab CI é melhor que GitHub Actions para Kotlin? Não por causa da linguagem. GitLab CI costuma ser melhor quando a empresa já usa GitLab como plataforma completa. GitHub Actions costuma ser mais natural quando o repositório vive no GitHub e o time quer um ecossistema grande de actions prontas.\nDevo rodar detekt e ktlint antes ou depois dos testes? Em projetos pequenos, pode rodar tudo junto. Em projetos maiores, rode compilação e testes unitários primeiro para feedback rápido, depois qualidade e integração.\nCI/CD para Android Kotlin é diferente? A ideia é a mesma, mas as tarefas mudam: testDebugUnitTest, lintDebug, build de APK/AAB e, quando necessário, testes instrumentados com emulador ou device farm.\nConclusão CI/CD para Kotlin em 2026 não é apenas um YAML bonito no repositório. É uma rede de segurança para entregar software com menos medo: Gradle previsível, testes confiáveis, qualidade automatizada, secrets protegidos e deploy controlado. Comece pequeno com build, teste e qualidade. Depois adicione Docker, ambientes, approvals e observabilidade. O importante é que cada mudança no projeto Kotlin passe por um caminho repetível antes de virar produção.\nPipelines semelhantes podem ser configurados para projetos Go, Python e Rust, mas a disciplina é a mesma: automatizar o caminho crítico e deixar o time livre para escrever código melhor.\n","permalink":"https://kotlin.dev.br/guias/guia-kotlin-ci-cd/","summary":"\u003cp\u003eCI/CD é o conjunto de práticas que transforma um projeto Kotlin em software entregue com previsibilidade: cada mudança compila, roda testes, passa por análise de qualidade, gera artefatos e chega ao ambiente certo sem depender de uma sequência manual frágil. Em Kotlin, isso vale para Android, backend com Ktor ou Spring Boot, bibliotecas multiplataforma, CLIs e serviços que rodam em Docker ou Kubernetes.\u003c/p\u003e\n\u003cp\u003eEste guia foi atualizado para 2026 com um foco prático: montar pipelines úteis em GitHub Actions e GitLab CI, configurar Gradle para ambientes de integração contínua, encaixar testes, detekt, ktlint, cache, Docker e deploy sem transformar o pipeline em um labirinto. Se você ainda está escolhendo a stack do projeto, leia também o guia de \u003ca href=\"/guias/kotlin-para-backend/\"\u003eKotlin para backend\u003c/a\u003e, o artigo de \u003ca href=\"/blog/kotlin-spring-boot/\"\u003eKotlin com Spring Boot\u003c/a\u003e e o material de \u003ca href=\"/blog/detekt-ktlint-kotlin-qualidade-2026/\"\u003edetekt e ktlint em Kotlin\u003c/a\u003e.\u003c/p\u003e","title":"CI/CD para Kotlin em 2026: GitHub Actions, GitLab CI, Gradle e Deploy"},{"content":"Conseguir um emprego como desenvolvedor Kotlin é totalmente possível, mesmo para quem esta comecando. O mercado brasileiro esta aquecido, com empresas de todos os portes buscando profissionais qualificados. Neste guia, vou compartilhar estrategias práticas para você conquistar sua vaga. Se você está mirando o primeiro emprego, veja também a referência de salário para desenvolvedor Kotlin júnior para calibrar expectativa antes de negociar.\nO Mercado Kotlin no Brasil em 2025-2026 O mercado para Kotlin no Brasil esta em expansao por vários fatores:\nAndroid: Continua sendo a plataforma mobile dominante no Brasil, e Kotlin é a linguagem oficial Backend: Cada vez mais empresas migram de Java para Kotlin no servidor Multiplatform: KMP cria demanda por desenvolvedores que conhecem Kotlin em múltiplos contextos Fintechs: O setor financeiro brasileiro adota Kotlin agressivamente Segundo dados de plataformas como LinkedIn e Glassdoor, as vagas Kotlin no Brasil cresceram mais de 40% nos ultimos dois anos. E a tendencia e de aceleracao.\nHabilidades Essenciais Para Android Se você quer entrar pelo caminho mobile, precisa dominar:\n// Jetpack Compose - Obrigatorio para vagas Android modernas @Composable fun LoginScreen( viewModel: LoginViewModel = hiltViewModel() ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() Column( modifier = Modifier .fillMaxSize() .padding(24.dp), verticalArrangement = Arrangement.Center ) { var email by remember { mutableStateOf(\u0026#34;\u0026#34;) } var senha by remember { mutableStateOf(\u0026#34;\u0026#34;) } OutlinedTextField( value = email, onValueChange = { email = it }, label = { Text(\u0026#34;E-mail\u0026#34;) }, modifier = Modifier.fillMaxWidth(), keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Email ) ) Spacer(modifier = Modifier.height(16.dp)) OutlinedTextField( value = senha, onValueChange = { senha = it }, label = { Text(\u0026#34;Senha\u0026#34;) }, visualTransformation = PasswordVisualTransformation(), modifier = Modifier.fillMaxWidth() ) Spacer(modifier = Modifier.height(24.dp)) Button( onClick = { viewModel.login(email, senha) }, modifier = Modifier.fillMaxWidth(), enabled = !uiState.loading ) { if (uiState.loading) { CircularProgressIndicator(modifier = Modifier.size(20.dp)) } else { Text(\u0026#34;Entrar\u0026#34;) } } } } Alem de Compose, você precisa conhecer:\nArquitetura MVVM com ViewModel Coroutines e Flow Hilt para injeção de dependência Room para persistencia local Retrofit ou Ktor Client para networking Navigation Compose Para Backend // Spring Boot - Stack mais pedida para backend @Service class ProductService( private val repository: ProductRepository, private val cacheService: CacheService ) { suspend fun findById(id: String): Product? { return cacheService.get(\u0026#34;product:$id\u0026#34;) ?: repository.findById(id)?.also { product -\u0026gt; cacheService.set(\u0026#34;product:$id\u0026#34;, product, ttl = 5.minutes) } } @Transactional suspend fun create(request: CreateProductRequest): Product { val product = Product( id = UUID.randomUUID().toString(), nome = request.nome, preco = request.preco, descricao = request.descricao, criadoEm = Instant.now() ) return repository.save(product) } } Para backend, as habilidades mais pedidas são:\nSpring Boot com Kotlin APIs REST e/ou GraphQL Banco de dados (PostgreSQL, MongoDB) Docker e deploy básico Testes automatizados Mensageria (Kafka, RabbitMQ) Construindo seu Portfolio O portfolio e mais importante que o curriculo para vagas de desenvolvimento. Aqui estao projetos que impressionam recrutadores:\nProjeto 1: App Completo com Arquitetura Limpa Crie um app Android com:\nJetpack Compose para UI MVVM com Clean Architecture Consumo de API publica Persistencia local com Room Testes unitarios e de UI Projeto 2: API REST com Kotlin // Exemplo de API bem estruturada para portfolio // Mostra que voce entende arquitetura e boas praticas @RestController @RequestMapping(\u0026#34;/api/v1/tasks\u0026#34;) class TaskController(private val taskService: TaskService) { @GetMapping suspend fun listAll( @RequestParam(defaultValue = \u0026#34;1\u0026#34;) page: Int, @RequestParam(defaultValue = \u0026#34;20\u0026#34;) size: Int, @RequestParam(required = false) status: TaskStatus? ): ResponseEntity\u0026lt;PagedResponse\u0026lt;TaskDTO\u0026gt;\u0026gt; { val tasks = taskService.list(page, size, status) return ResponseEntity.ok(tasks) } @PostMapping suspend fun create( @Valid @RequestBody request: CreateTaskRequest ): ResponseEntity\u0026lt;TaskDTO\u0026gt; { val task = taskService.create(request) return ResponseEntity .created(URI(\u0026#34;/api/v1/tasks/${task.id}\u0026#34;)) .body(task) } @PutMapping(\u0026#34;/{id}\u0026#34;) suspend fun update( @PathVariable id: String, @Valid @RequestBody request: UpdateTaskRequest ): ResponseEntity\u0026lt;TaskDTO\u0026gt; { val task = taskService.update(id, request) return ResponseEntity.ok(task) } } Projeto 3: Contribuicao Open Source Contribuir para projetos open source em Kotlin mostra iniciativa e capacidade de trabalhar em equipe. Procure projetos no GitHub com tags como \u0026ldquo;good first issue\u0026rdquo; ou \u0026ldquo;help wanted\u0026rdquo; em repositórios Kotlin.\nPreparacao para Entrevistas Perguntas Tecnicas Comuns Prepare-se para explicar conceitos como:\n// Null safety - Tema frequente em entrevistas // Explique a diferenca entre ?, !!, ?., ?: val nome: String? = getNome() // Safe call val tamanho = nome?.length // Int? - pode ser null // Elvis operator val tamanhoOuZero = nome?.length ?: 0 // Int - nunca null // Not-null assertion (evitar em producao) val tamanhoForced = nome!!.length // Lanca exception se null // Smart cast if (nome != null) { println(nome.length) // Aqui, nome e String (nao nullable) } // Coroutines - Outro tema frequente // Explique suspend functions, dispatchers, structured concurrency suspend fun exemploCoroutines() = coroutineScope { // launch - fire and forget launch { tarefaAssincrona() } // async - retorna resultado val resultado = async { calcularAlgo() } println(resultado.await()) // withContext - trocar dispatcher val dados = withContext(Dispatchers.IO) { carregarDoBancoDeDados() } } Live Coding Muitas empresas pedem live coding. Pratique:\nAlgoritmos básicos em Kotlin manipulação de coleções (map, filter, reduce, groupBy) Criação de classes e interfaces Tratamento de erros // Exemplo tipico de live coding // \u0026#34;Agrupe pedidos por status e calcule o total de cada grupo\u0026#34; fun agruparPedidos(pedidos: List\u0026lt;Pedido\u0026gt;): Map\u0026lt;String, ResumoGrupo\u0026gt; { return pedidos .groupBy { it.status } .mapValues { (status, pedidosGrupo) -\u0026gt; ResumoGrupo( status = status, quantidade = pedidosGrupo.size, valorTotal = pedidosGrupo.sumOf { it.valor }, ticketMedio = pedidosGrupo.map { it.valor }.average() ) } } Estrategias de Busca de Emprego Onde Encontrar Vagas LinkedIn: Configure alertas para \u0026ldquo;Kotlin Developer\u0026rdquo;, \u0026ldquo;Android Kotlin\u0026rdquo;, \u0026ldquo;Kotlin Backend\u0026rdquo; GitHub Jobs: Vagas em empresas que usam Kotlin open source Comunidades: Grupos Kotlin Brasil no Telegram e Discord frequentemente postam vagas Empresas específicas: Acompanhe paginas de carreiras de empresas como Nubank, Itau, iFood, PicPay Networking Participe ativamente da comunidade:\nFrequente meetups de Kotlin e Android Contribua em discussoes no Stack Overflow em português Escreva artigos tecnicos sobre Kotlin Participe de hackathons Curriculo Efetivo Seu curriculo deve destacar:\nProjetos reais (mesmo pessoais) com Kotlin Tecnologias específicas que você domina Resultados mensurareis (quando possível) Link para GitHub com código de qualidade Faixa Salarial no Brasil Para dar uma referência de mercado (valores aproximados em 2025-2026):\nJunior: R$ 3.000 a R$ 6.000 (CLT) Pleno: R$ 7.000 a R$ 14.000 (CLT) Senior: R$ 15.000 a R$ 25.000 (CLT) Remoto internacional (PJ): R$ 20.000 a R$ 45.000+ Essas faixas variam por região, porte da empresa e especializacao. Backend enterprise e posicoes com KMP tendem a pagar mais.\nDicas Finais Nao espere estar pronto: Comece a aplicar quando tiver conhecimento básico solido. Você vai aprender muito no processo de entrevistas.\nSeja consistente: Estude e pratique Kotlin todos os dias, mesmo que por pouco tempo. Consistencia supera intensidade.\nDocumente sua jornada: Mantenha seu GitHub atualizado, escreva sobre o que aprende, compartilhe conhecimento.\nAceite feedback: Entrevistas são oportunidades de aprendizado. Peca feedback quando possível e use para melhorar.\nFoque em fundamentos: Empresas valorizam quem entende bem orientacao a objetos, estruturas de dados, arquitetura de software e boas práticas. Kotlin e a ferramenta, mas os fundamentos são o alicerce.\nConclusão Conseguir um emprego com Kotlin e uma questao de preparacao, persistencia e estrategia. O mercado esta favoravel, as oportunidades são reais e a demanda só cresce. Invista nas habilidades certas, construa um portfolio solido, prepare-se para entrevistas e seja ativo na comunidade. Adicionar Go ou Python ao seu currículo também abre portas em mais empresas. Sua vaga esta mais perto do que você imagina.\n","permalink":"https://kotlin.dev.br/blog/como-conseguir-emprego-kotlin/","summary":"\u003cp\u003eConseguir um emprego como desenvolvedor Kotlin é totalmente possível, mesmo para quem esta comecando. O mercado brasileiro esta aquecido, com empresas de todos os portes buscando profissionais qualificados. Neste guia, vou compartilhar estrategias práticas para você conquistar sua vaga. Se você está mirando o primeiro emprego, veja também a referência de \u003ca href=\"/carreira/salario-dev-kotlin-junior/\"\u003esalário para desenvolvedor Kotlin júnior\u003c/a\u003e para calibrar expectativa antes de negociar.\u003c/p\u003e\n\u003ch2 id=\"o-mercado-kotlin-no-brasil-em-2025-2026\"\u003eO Mercado Kotlin no Brasil em 2025-2026\u003c/h2\u003e\n\u003cp\u003eO mercado para Kotlin no Brasil esta em expansao por vários fatores:\u003c/p\u003e","title":"Como Conseguir Emprego com Kotlin: Guia Completo | Kotlin Brasil"},{"content":"O Gradle é o sistema de build padrão para projetos Kotlin e Android, e quando combinado com o Kotlin DSL (arquivos .kts), oferece autocompletion, verificação de tipos em tempo de compilação e toda a expressividade da linguagem. Neste tutorial, vamos explorar desde a configuração básica do build.gradle.kts até tópicos avançados como projetos multi-módulo, version catalogs e criação de tasks customizadas.\nPor que Kotlin DSL no Gradle? Tradicionalmente, arquivos Gradle usam Groovy, uma linguagem dinâmica sem verificação de tipos. Com Kotlin DSL, você ganha suporte completo do IDE — autocompletion, navegação para definições, refatoração e erros em tempo de compilação. Como o arquivo de build é Kotlin puro, você pode usar funções, classes, condicionais e tudo que a linguagem oferece diretamente na configuração.\nPasso 1: Estrutura Básica do build.gradle.kts Vamos começar com a estrutura fundamental de um projeto Kotlin com Gradle:\n// build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.0.0\u0026#34; application } group = \u0026#34;com.exemplo\u0026#34; version = \u0026#34;1.0.0\u0026#34; application { mainClass.set(\u0026#34;com.exemplo.MainKt\u0026#34;) } repositories { mavenCentral() google() } dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-core:2.3.12\u0026#34;) testImplementation(kotlin(\u0026#34;test\u0026#34;)) testImplementation(\u0026#34;org.junit.jupiter:junit-jupiter:5.10.3\u0026#34;) } tasks.test { useJUnitPlatform() } kotlin { jvmToolchain(21) } Cada seção tem uma responsabilidade clara: plugins ativa funcionalidades, repositories define de onde baixar dependências, dependencies lista as bibliotecas necessárias, e kotlin configura o compilador.\nPasso 2: Gerenciando Dependências No Gradle, as dependências são organizadas por configurações que definem quando e como elas são usadas:\ndependencies { // Disponível em compile-time e runtime implementation(\u0026#34;com.squareup.okhttp3:okhttp:4.12.0\u0026#34;) // Disponível em compile-time, mas nao exposta para consumidores implementation(\u0026#34;com.google.code.gson:gson:2.11.0\u0026#34;) // Exposta para consumidores da sua biblioteca api(\u0026#34;org.jetbrains.exposed:exposed-core:0.52.0\u0026#34;) // Apenas em compile-time (ex: processadores de annotation) compileOnly(\u0026#34;org.projectlombok:lombok:1.18.34\u0026#34;) // Apenas em runtime runtimeOnly(\u0026#34;org.postgresql:postgresql:42.7.3\u0026#34;) // Apenas para testes testImplementation(\u0026#34;io.mockk:mockk:1.13.12\u0026#34;) // Plataforma (BOM) para alinhar versoes implementation(platform(\u0026#34;io.ktor:ktor-bom:2.3.12\u0026#34;)) implementation(\u0026#34;io.ktor:ktor-server-core\u0026#34;) // versao vem do BOM } A diferença entre implementation e api é crucial em projetos multi-módulo: api expõe a dependência para quem consome seu módulo, enquanto implementation a mantém privada. Sempre prefira implementation para reduzir o classpath transitivo.\nPasso 3: Plugins Plugins estendem as capacidades do Gradle. Há duas formas de aplicá-los:\n// build.gradle.kts plugins { // Plugin do repositório de plugins do Gradle kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.0.0\u0026#34; kotlin(\u0026#34;plugin.serialization\u0026#34;) version \u0026#34;2.0.0\u0026#34; // Plugin por ID id(\u0026#34;com.github.johnrengelman.shadow\u0026#34;) version \u0026#34;8.1.1\u0026#34; // Plugin built-in do Gradle (sem versao) application `java-library` } Para projetos multi-módulo, defina versões de plugins uma única vez no settings.gradle.kts:\n// settings.gradle.kts pluginManagement { plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.0.0\u0026#34; kotlin(\u0026#34;plugin.serialization\u0026#34;) version \u0026#34;2.0.0\u0026#34; } } Depois, nos módulos, aplique sem especificar versão:\n// modulo/build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) } Passo 4: Criando Tasks Customizadas Tasks são a unidade fundamental de trabalho no Gradle. Você pode criar tasks personalizadas usando Kotlin:\n// build.gradle.kts tasks.register(\u0026#34;gerarRelatorio\u0026#34;) { group = \u0026#34;documentacao\u0026#34; description = \u0026#34;Gera relatório de dependências do projeto\u0026#34; doLast { val arquivo = file(\u0026#34;$buildDir/relatorio.txt\u0026#34;) arquivo.parentFile.mkdirs() val dependências = configurations[\u0026#34;runtimeClasspath\u0026#34;] .resolvedConfiguration .resolvedArtifacts .map { \u0026#34;${it.moduleVersion.id}\u0026#34; } .sorted() arquivo.writeText(dependências.joinToString(\u0026#34;\\n\u0026#34;)) println(\u0026#34;Relatório gerado em: ${arquivo.absolutePath}\u0026#34;) } } tasks.register\u0026lt;Copy\u0026gt;(\u0026#34;copiarConfiguracoes\u0026#34;) { from(\u0026#34;src/main/resources/config\u0026#34;) into(\u0026#34;$buildDir/config\u0026#34;) include(\u0026#34;*.yaml\u0026#34;, \u0026#34;*.properties\u0026#34;) filter { linha -\u0026gt; linha.replace(\u0026#34;localhost\u0026#34;, System.getenv(\u0026#34;DB_HOST\u0026#34;) ?: \u0026#34;localhost\u0026#34;) } } Tasks tipadas como Copy, Jar, Exec oferecem APIs específicas. Para criar tasks reutilizáveis com lógica complexa, use classes:\nabstract class GerarDocTask : DefaultTask() { @get:Input abstract val modulo: Property\u0026lt;String\u0026gt; @get:OutputDirectory abstract val saida: DirectoryProperty @TaskAction fun executar() { val dir = saida.get().asFile dir.mkdirs() File(dir, \u0026#34;docs.txt\u0026#34;).writeText(\u0026#34;Documentação do módulo: ${modulo.get()}\u0026#34;) } } tasks.register\u0026lt;GerarDocTask\u0026gt;(\u0026#34;gerarDoc\u0026#34;) { modulo.set(\u0026#34;core\u0026#34;) saida.set(layout.buildDirectory.dir(\u0026#34;docs\u0026#34;)) } Passo 5: Projetos Multi-Módulo Projetos grandes se beneficiam de uma arquitetura modular. Veja a estrutura típica:\n// settings.gradle.kts rootProject.name = \u0026#34;meu-projeto\u0026#34; include(\u0026#34;:core\u0026#34;) include(\u0026#34;:api\u0026#34;) include(\u0026#34;:app\u0026#34;) Cada módulo tem seu próprio build.gradle.kts e pode depender de outros:\n// api/build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) } dependencies { implementation(project(\u0026#34;:core\u0026#34;)) implementation(\u0026#34;io.ktor:ktor-server-core:2.3.12\u0026#34;) } Para compartilhar configurações entre módulos, use subprojects ou allprojects no build raiz:\n// build.gradle.kts (raiz) subprojects { apply(plugin = \u0026#34;org.jetbrains.kotlin.jvm\u0026#34;) repositories { mavenCentral() } dependencies { testImplementation(kotlin(\u0026#34;test\u0026#34;)) } tasks.withType\u0026lt;org.jetbrains.kotlin.gradle.tasks.KotlinCompile\u0026gt; { compilerOptions { jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21) } } } Passo 6: Version Catalogs O Version Catalog (introduzido no Gradle 7.0) centraliza todas as versões de dependências em um único arquivo TOML:\n// gradle/libs.versions.toml [versions] kotlin = \u0026#34;2.0.0\u0026#34; ktor = \u0026#34;2.3.12\u0026#34; exposed = \u0026#34;0.52.0\u0026#34; coroutines = \u0026#34;1.8.1\u0026#34; junit = \u0026#34;5.10.3\u0026#34; [libraries] ktor-server-core = { module = \u0026#34;io.ktor:ktor-server-core\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } ktor-server-netty = { module = \u0026#34;io.ktor:ktor-server-netty\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } exposed-core = { module = \u0026#34;org.jetbrains.exposed:exposed-core\u0026#34;, version.ref = \u0026#34;exposed\u0026#34; } exposed-dao = { module = \u0026#34;org.jetbrains.exposed:exposed-dao\u0026#34;, version.ref = \u0026#34;exposed\u0026#34; } coroutines-core = { module = \u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core\u0026#34;, version.ref = \u0026#34;coroutines\u0026#34; } junit-jupiter = { module = \u0026#34;org.junit.jupiter:junit-jupiter\u0026#34;, version.ref = \u0026#34;junit\u0026#34; } [bundles] ktor-server = [\u0026#34;ktor-server-core\u0026#34;, \u0026#34;ktor-server-netty\u0026#34;] exposed = [\u0026#34;exposed-core\u0026#34;, \u0026#34;exposed-dao\u0026#34;] [plugins] kotlin-jvm = { id = \u0026#34;org.jetbrains.kotlin.jvm\u0026#34;, version.ref = \u0026#34;kotlin\u0026#34; } No build.gradle.kts, use as referências tipadas:\ndependencies { implementation(libs.coroutines.core) implementation(libs.bundles.ktor.server) implementation(libs.bundles.exposed) testImplementation(libs.junit.jupiter) } O Version Catalog gera acessors type-safe, então o IDE oferece autocompletion completo. Bundles agrupam dependências relacionadas, simplificando a declaração em múltiplos módulos.\nPasso 7: buildSrc para Lógica Compartilhada O diretório buildSrc/ é compilado automaticamente pelo Gradle e disponibilizado em todos os scripts de build. Use-o para convention plugins e constantes:\n// buildSrc/build.gradle.kts plugins { `kotlin-dsl` } repositories { mavenCentral() } // buildSrc/src/main/kotlin/kotlin-conventions.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) } group = \u0026#34;com.exemplo\u0026#34; repositories { mavenCentral() } kotlin { jvmToolchain(21) } tasks.test { useJUnitPlatform() } Depois, aplique em qualquer módulo:\n// core/build.gradle.kts plugins { id(\u0026#34;kotlin-conventions\u0026#34;) } dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1\u0026#34;) } O buildSrc é excelente para eliminar duplicação entre módulos. Para projetos muito grandes, considere migrar para Composite Builds com convention plugins em um diretório separado como build-logic/.\nErros Comuns 1. Misturar sintaxe Groovy com Kotlin DSL: Strings com aspas simples ('valor') não existem em Kotlin. Use sempre aspas duplas. Atribuições com = são obrigatórias no Kotlin DSL (Groovy permite omitir).\n2. Não usar kotlin(\u0026quot;test\u0026quot;) para testes: Essa dependência inclui automaticamente as assertions do Kotlin e o adapter correto para a plataforma. Sem ela, você precisa importar assertions do JUnit diretamente.\n3. Esquecer useJUnitPlatform(): Sem essa configuração na task test, o Gradle não encontra nem executa os testes JUnit 5. Esse é um dos erros mais frustrantes para iniciantes.\n4. Version Catalog com nomes inválidos: No TOML, use hífens nos nomes de bibliotecas. O Gradle converte para pontos nos acessors Kotlin (ex: ktor-server-core vira libs.ktor.server.core).\n5. buildSrc recriando cache a cada mudança: Qualquer alteração no buildSrc invalida todo o cache do Gradle. Para projetos grandes, prefira Composite Builds que oferecem invalidação granular.\nConclusão e Próximos Passos Neste tutorial, exploramos o Gradle com Kotlin DSL de ponta a ponta: desde a estrutura básica do build.gradle.kts até técnicas avançadas como version catalogs, projetos multi-módulo e buildSrc. Dominar o Gradle é essencial para qualquer desenvolvedor Kotlin, pois o sistema de build impacta diretamente a produtividade e manutenibilidade do projeto.\nComo próximos passos, estude o Gradle Configuration Cache para builds mais rápidos, explore plugins como Shadow para fat JARs e Detekt para análise estática de código Kotlin. Para aprofundar seu conhecimento em Kotlin DSL, confira nosso tutorial dedicado sobre como criar DSLs em Kotlin.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-gradle-tutorial/","summary":"\u003cp\u003eO \u003cstrong\u003eGradle\u003c/strong\u003e é o sistema de build padrão para projetos Kotlin e Android, e quando combinado com o \u003cstrong\u003eKotlin DSL\u003c/strong\u003e (arquivos \u003ccode\u003e.kts\u003c/code\u003e), oferece autocompletion, verificação de tipos em tempo de compilação e toda a expressividade da linguagem. Neste tutorial, vamos explorar desde a configuração básica do \u003ccode\u003ebuild.gradle.kts\u003c/code\u003e até tópicos avançados como projetos multi-módulo, version catalogs e criação de tasks customizadas.\u003c/p\u003e\n\u003ch2 id=\"por-que-kotlin-dsl-no-gradle\"\u003ePor que Kotlin DSL no Gradle?\u003c/h2\u003e\n\u003cp\u003eTradicionalmente, arquivos Gradle usam Groovy, uma linguagem dinâmica sem verificação de tipos. Com Kotlin \u003ca href=\"/glossario/dsl/\"\u003eDSL\u003c/a\u003e, você ganha suporte completo do IDE — autocompletion, navegação para definições, refatoração e erros em tempo de compilação. Como o arquivo de build é Kotlin puro, você pode usar \u003ca href=\"/glossario/fun/\"\u003efunções\u003c/a\u003e, \u003ca href=\"/glossario/class/\"\u003eclasses\u003c/a\u003e, condicionais e tudo que a linguagem oferece diretamente na configuração.\u003c/p\u003e","title":"Gradle com Kotlin DSL Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Kotlin não é apenas uma linguagem para desenvolvimento Android. Ela se tornou uma escolha cada vez mais popular para o desenvolvimento backend, oferecendo uma combinação poderosa de produtividade, segurança de tipos e excelente suporte a programação assíncrona. Neste guia, exploramos como usar Kotlin para construir aplicações server-side robustas e escaláveis, cobrindo os principais frameworks e práticas do ecossistema.\nPor Que Escolher Kotlin para Backend O desenvolvimento backend com Kotlin traz diversas vantagens em relação ao uso de Java puro. A linguagem mantém total compatibilidade com o ecossistema JVM enquanto oferece recursos modernos que aumentam a produtividade do desenvolvedor.\nAs principais razões para adotar Kotlin no backend são:\nCoroutines nativas: suporte a programação assíncrona sem a complexidade de reactive streams ou callbacks Null safety: eliminação de NullPointerException em tempo de compilação Concisão: menos código boilerplate resulta em manutenção mais fácil Ecossistema JVM: acesso a todas as bibliotecas Java existentes, incluindo Spring, Hibernate, e centenas de outras DSL builders: criação de APIs internas expressivas e type-safe Suporte empresarial: Spring Boot, Quarkus e Micronaut oferecem suporte oficial a Kotlin Empresas como Netflix, Amazon, Uber e diversas fintechs brasileiras já utilizam Kotlin em seus backends de produção. A linguagem provou ser madura o suficiente para aplicações de missão crítica em larga escala. Se você quer comparar Kotlin com outras linguagens backend populares, veja também Go para backend cloud-native e Rust para web backend de alta performance. Para uma comparação detalhada entre os frameworks server-side disponíveis, consulte nosso guia de Server-Side Frameworks.\nSpring Boot com Kotlin Spring Boot é o framework backend mais utilizado no ecossistema JVM e oferece suporte de primeira classe a Kotlin desde a versão 5.0 do Spring Framework. A combinação de Spring Boot com Kotlin resulta em código significativamente mais limpo e expressivo.\nConfiguração Inicial // build.gradle.kts plugins { id(\u0026#34;org.springframework.boot\u0026#34;) version \u0026#34;3.3.0\u0026#34; id(\u0026#34;io.spring.dependency-management\u0026#34;) version \u0026#34;1.1.5\u0026#34; kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.0.0\u0026#34; kotlin(\u0026#34;plugin.spring\u0026#34;) version \u0026#34;2.0.0\u0026#34; kotlin(\u0026#34;plugin.jpa\u0026#34;) version \u0026#34;2.0.0\u0026#34; } dependencies { implementation(\u0026#34;org.springframework.boot:spring-boot-starter-web\u0026#34;) implementation(\u0026#34;org.springframework.boot:spring-boot-starter-data-jpa\u0026#34;) implementation(\u0026#34;com.fasterxml.jackson.module:jackson-module-kotlin\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlin:kotlin-reflect\u0026#34;) } O plugin kotlin-spring garante que classes Spring sejam automaticamente abertas (open), algo necessário porque Kotlin torna classes final por padrão. O plugin kotlin-jpa gera construtores sem argumentos para entidades JPA.\nCriando uma API REST Completa // Entidade @Entity data class Produto( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0, val nome: String, val descricao: String?, val preco: Double, val ativo: Boolean = true ) // Repository interface ProdutoRepository : JpaRepository\u0026lt;Produto, Long\u0026gt; { fun findByAtivoTrue(): List\u0026lt;Produto\u0026gt; fun findByNomeContainingIgnoreCase(nome: String): List\u0026lt;Produto\u0026gt; } // Service @Service class ProdutoService(private val repository: ProdutoRepository) { fun listarAtivos(): List\u0026lt;Produto\u0026gt; = repository.findByAtivoTrue() fun buscarPorId(id: Long): Produto = repository.findByIdOrNull(id) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, \u0026#34;Produto nao encontrado\u0026#34;) fun criar(produto: Produto): Produto = repository.save(produto) fun atualizar(id: Long, dados: Produto): Produto { val existente = buscarPorId(id) val atualizado = existente.copy( nome = dados.nome, descricao = dados.descricao, preco = dados.preco ) return repository.save(atualizado) } fun deletar(id: Long) { val produto = buscarPorId(id) repository.save(produto.copy(ativo = false)) } } // Controller @RestController @RequestMapping(\u0026#34;/api/produtos\u0026#34;) class ProdutoController(private val service: ProdutoService) { @GetMapping fun listar() = service.listarAtivos() @GetMapping(\u0026#34;/{id}\u0026#34;) fun buscar(@PathVariable id: Long) = service.buscarPorId(id) @PostMapping @ResponseStatus(HttpStatus.CREATED) fun criar(@RequestBody produto: Produto) = service.criar(produto) @PutMapping(\u0026#34;/{id}\u0026#34;) fun atualizar(@PathVariable id: Long, @RequestBody produto: Produto) = service.atualizar(id, produto) @DeleteMapping(\u0026#34;/{id}\u0026#34;) @ResponseStatus(HttpStatus.NO_CONTENT) fun deletar(@PathVariable id: Long) = service.deletar(id) } Note como o uso de data classes com copy() torna a atualização de entidades elegante e imutável. A injeção de dependência via construtor é a forma natural em Kotlin, eliminando a necessidade de @Autowired. Para mais sobre injeção de dependência, veja nosso guia de Injeção de Dependência com Koin e Hilt.\nKtor: Framework Nativo de Kotlin Ktor é um framework assíncrono desenvolvido pela JetBrains, construído do zero para Kotlin. Ele é leve, modular e usa coroutines nativamente em todo o seu core.\nfun main() { embeddedServer(Netty, port = 8080) { configurarRouting() configurarSerialization() }.start(wait = true) } fun Application.configurarSerialization() { install(ContentNegotiation) { json(Json { prettyPrint = true isLenient = true }) } } fun Application.configurarRouting() { routing { route(\u0026#34;/api/tarefas\u0026#34;) { get { val tarefas = tarefaService.listarTodas() call.respond(tarefas) } get(\u0026#34;/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toLongOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest, \u0026#34;ID invalido\u0026#34;) val tarefa = tarefaService.buscarPorId(id) if (tarefa != null) { call.respond(tarefa) } else { call.respond(HttpStatusCode.NotFound, \u0026#34;Tarefa nao encontrada\u0026#34;) } } post { val tarefa = call.receive\u0026lt;Tarefa\u0026gt;() val criada = tarefaService.criar(tarefa) call.respond(HttpStatusCode.Created, criada) } } } } Ktor se destaca pela abordagem modular onde cada funcionalidade é um plugin instalável, pelo uso nativo de coroutines em todas as operações de I/O e pela DSL expressiva para definição de rotas. Para um aprofundamento completo, confira nosso guia dedicado ao Ktor.\nComparação entre Frameworks Backend Característica Spring Boot Ktor Quarkus Micronaut Maturidade Muito alta Alta Alta Alta Suporte Kotlin Excelente Nativo Bom Bom Coroutines Suportado Nativo Limitado Limitado Tempo de startup Moderado Rápido Muito rápido Muito rápido Ecossistema Enorme Crescente Grande Grande Curva de aprendizado Moderada Baixa Moderada Moderada GraalVM Native Suportado Suportado Excelente Excelente Banco de Dados e Persistência Para persistência de dados em Kotlin, existem diversas opções além do JPA/Hibernate tradicional:\nExposed: ORM Nativo de Kotlin // Definição de tabela object Usuarios : Table(\u0026#34;usuarios\u0026#34;) { val id = integer(\u0026#34;id\u0026#34;).autoIncrement() val nome = varchar(\u0026#34;nome\u0026#34;, 255) val email = varchar(\u0026#34;email\u0026#34;, 255).uniqueIndex() val criadoEm = datetime(\u0026#34;criado_em\u0026#34;).defaultExpression(CurrentDateTime) override val primaryKey = PrimaryKey(id) } // Query DSL fun buscarUsuariosAtivos(): List\u0026lt;UsuarioDTO\u0026gt; { return transaction { Usuarios .selectAll() .where { Usuarios.nome like \u0026#34;%kotlin%\u0026#34; } .map { row -\u0026gt; UsuarioDTO( id = row[Usuarios.id], nome = row[Usuarios.nome], email = row[Usuarios.email] ) } } } Exposed oferece duas APIs: uma DSL type-safe para queries e uma API DAO mais similar ao Active Record. Ambas são idiomáticas em Kotlin e aproveitam o sistema de tipos da linguagem.\nProgramação Assíncrona com Coroutines Uma das maiores vantagens de Kotlin no backend é o suporte nativo a coroutines para operações assíncronas. Isso é especialmente importante para aplicações que fazem muitas chamadas de I/O, como requisições a APIs externas, consultas a bancos de dados e operações de arquivo.\n@Service class PedidoService( private val pedidoRepo: PedidoRepository, private val pagamentoClient: PagamentoClient, private val notificacaoService: NotificacaoService ) { suspend fun processarPedido(pedidoId: Long) = coroutineScope { val pedido = pedidoRepo.buscarPorId(pedidoId) // Executar pagamento e notificacao em paralelo val pagamentoDeferred = async { pagamentoClient.processar(pedido) } val notificacaoDeferred = async { notificacaoService.enviar(pedido) } val pagamento = pagamentoDeferred.await() val notificacao = notificacaoDeferred.await() pedidoRepo.atualizar(pedido.copy( status = if (pagamento.sucesso) \u0026#34;PAGO\u0026#34; else \u0026#34;FALHA\u0026#34;, notificado = notificacao.enviado )) } } Para dominar coroutines e entender seus padrões avançados, consulte nosso guia completo de Coroutines e o guia de Kotlin Flow.\nSegurança e Autenticação A segurança em aplicações backend Kotlin geralmente é implementada com Spring Security ou com os plugins de autenticação do Ktor:\n// Spring Security com Kotlin @Configuration @EnableWebSecurity class SecurityConfig { @Bean fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { http { csrf { disable() } authorizeHttpRequests { authorize(\u0026#34;/api/public/**\u0026#34;, permitAll) authorize(\u0026#34;/api/admin/**\u0026#34;, hasRole(\u0026#34;ADMIN\u0026#34;)) authorize(anyRequest, authenticated) } oauth2ResourceServer { jwt { } } } return http.build() } } Conclusão e Recomendações Kotlin é uma escolha excelente para desenvolvimento backend, combinando a maturidade do ecossistema JVM com recursos modernos de linguagem. Para projetos que já usam Spring, a adoção de Kotlin é natural e traz ganhos imediatos. Para novos projetos que priorizam performance e leveza, Ktor é uma alternativa nativa e elegante.\nRecomendamos começar com o framework que sua equipe já conhece e gradualmente explorar os recursos específicos de Kotlin. Para comparar abordagens de backend, confira como Go aborda o desenvolvimento server-side e como Python com FastAPI e Django resolve os mesmos problemas. Confira nossos tutoriais práticos para projetos backend completos e o glossário para referência rápida de termos técnicos.\n","permalink":"https://kotlin.dev.br/guias/kotlin-para-backend/","summary":"\u003cp\u003eKotlin não é apenas uma linguagem para desenvolvimento Android. Ela se tornou uma escolha cada vez mais popular para o desenvolvimento backend, oferecendo uma combinação poderosa de produtividade, segurança de tipos e excelente suporte a programação assíncrona. Neste guia, exploramos como usar Kotlin para construir aplicações server-side robustas e escaláveis, cobrindo os principais frameworks e práticas do ecossistema.\u003c/p\u003e\n\u003ch2 id=\"por-que-escolher-kotlin-para-backend\"\u003ePor Que Escolher Kotlin para Backend\u003c/h2\u003e\n\u003cp\u003eO desenvolvimento backend com Kotlin traz diversas vantagens em relação ao uso de Java puro. A linguagem mantém total compatibilidade com o ecossistema JVM enquanto oferece recursos modernos que aumentam a produtividade do desenvolvedor.\u003c/p\u003e","title":"Kotlin para Backend: Guia Completo de Desenvolvimento Server-Side | Kotlin Brasil"},{"content":"O Gradle é o sistema de build padrão para projetos Kotlin, tanto no Android quanto no backend. Com a adoção do Kotlin DSL nos scripts de build (build.gradle.kts em vez de build.gradle), a configuração ganha autocomplete, type safety e toda a expressividade do Kotlin. Compreender o Gradle profundamente e essencial para qualquer desenvolvedor Kotlin, pois ele controla compilação, dependências, testes, empacotamento e publicacao. Neste guia, vamos desde a estrutura básica até configurações avançadas com version catalogs, convention plugins e otimização de performance de build.\nGradle com Kotlin DSL: Por Que Migrar O Kotlin DSL oferece vantagens significativas sobre o Groovy DSL tradicional. Autocomplete no IDE funciona perfeitamente, erros de sintaxe são detectados em tempo de compilação é a refatoração e segura. A configuração se torna código Kotlin real, com tipagem forte e navegação de código.\n// build.gradle.kts - Kotlin DSL (recomendado) plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;1.9.22\u0026#34; application } group = \u0026#34;com.exemplo\u0026#34; version = \u0026#34;1.0.0\u0026#34; application { mainClass.set(\u0026#34;com.exemplo.MainKt\u0026#34;) } repositories { mavenCentral() } dependencies { implementation(\u0026#34;io.ktor:ktor-server-core:2.3.7\u0026#34;) testImplementation(kotlin(\u0026#34;test\u0026#34;)) } tasks.test { useJUnitPlatform() } Estrutura de um Projeto Multi-Modulo Projetos maiores se beneficiam de múltiplos modulos Gradle:\n// settings.gradle.kts rootProject.name = \u0026#34;meu-projeto\u0026#34; include(\u0026#34;:app\u0026#34;) include(\u0026#34;:core:domain\u0026#34;) include(\u0026#34;:core:data\u0026#34;) include(\u0026#34;:core:network\u0026#34;) include(\u0026#34;:feature:produtos\u0026#34;) include(\u0026#34;:feature:pedidos\u0026#34;) // Configuração de resolução de plugins pluginManagement { repositories { google() mavenCentral() gradlePluginPortal() } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } } Version Catalogs O Version Catalog centraliza todas as versões de dependências em um único arquivo libs.versions.toml:\n// gradle/libs.versions.toml [versions] kotlin = \u0026#34;1.9.22\u0026#34; ktor = \u0026#34;2.3.7\u0026#34; exposed = \u0026#34;0.46.0\u0026#34; koin = \u0026#34;3.5.3\u0026#34; coroutines = \u0026#34;1.7.3\u0026#34; logback = \u0026#34;1.4.14\u0026#34; junit = \u0026#34;5.10.1\u0026#34; mockk = \u0026#34;1.13.9\u0026#34; [libraries] ktor-server-core = { module = \u0026#34;io.ktor:ktor-server-core-jvm\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } ktor-server-netty = { module = \u0026#34;io.ktor:ktor-server-netty-jvm\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } ktor-server-content-negotiation = { module = \u0026#34;io.ktor:ktor-server-content-negotiation-jvm\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } ktor-serialization-json = { module = \u0026#34;io.ktor:ktor-serialization-kotlinx-json-jvm\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } exposed-core = { module = \u0026#34;org.jetbrains.exposed:exposed-core\u0026#34;, version.ref = \u0026#34;exposed\u0026#34; } exposed-dao = { module = \u0026#34;org.jetbrains.exposed:exposed-dao\u0026#34;, version.ref = \u0026#34;exposed\u0026#34; } exposed-jdbc = { module = \u0026#34;org.jetbrains.exposed:exposed-jdbc\u0026#34;, version.ref = \u0026#34;exposed\u0026#34; } koin-core = { module = \u0026#34;io.insert-koin:koin-core\u0026#34;, version.ref = \u0026#34;koin\u0026#34; } koin-ktor = { module = \u0026#34;io.insert-koin:koin-ktor\u0026#34;, version.ref = \u0026#34;koin\u0026#34; } coroutines-core = { module = \u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core\u0026#34;, version.ref = \u0026#34;coroutines\u0026#34; } coroutines-test = { module = \u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-test\u0026#34;, version.ref = \u0026#34;coroutines\u0026#34; } junit-jupiter = { module = \u0026#34;org.junit.jupiter:junit-jupiter\u0026#34;, version.ref = \u0026#34;junit\u0026#34; } mockk = { module = \u0026#34;io.mockk:mockk\u0026#34;, version.ref = \u0026#34;mockk\u0026#34; } [bundles] ktor-server = [\u0026#34;ktor-server-core\u0026#34;, \u0026#34;ktor-server-netty\u0026#34;, \u0026#34;ktor-server-content-negotiation\u0026#34;, \u0026#34;ktor-serialization-json\u0026#34;] exposed = [\u0026#34;exposed-core\u0026#34;, \u0026#34;exposed-dao\u0026#34;, \u0026#34;exposed-jdbc\u0026#34;] testing = [\u0026#34;junit-jupiter\u0026#34;, \u0026#34;mockk\u0026#34;, \u0026#34;coroutines-test\u0026#34;] [plugins] kotlin-jvm = { id = \u0026#34;org.jetbrains.kotlin.jvm\u0026#34;, version.ref = \u0026#34;kotlin\u0026#34; } kotlin-serialization = { id = \u0026#34;org.jetbrains.kotlin.plugin.serialization\u0026#34;, version.ref = \u0026#34;kotlin\u0026#34; } ktor = { id = \u0026#34;io.ktor.plugin\u0026#34;, version.ref = \u0026#34;ktor\u0026#34; } Usando no build.gradle.kts:\nplugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.serialization) alias(libs.plugins.ktor) } dependencies { implementation(libs.bundles.ktor.server) implementation(libs.bundles.exposed) implementation(libs.koin.core) implementation(libs.koin.ktor) implementation(libs.coroutines.core) testImplementation(libs.bundles.testing) } Convention Plugins Convention plugins permitem compartilhar configuração entre modulos sem duplicacao:\n// buildSrc/build.gradle.kts plugins { `kotlin-dsl` } repositories { mavenCentral() } // buildSrc/src/main/kotlin/kotlin-library-conventions.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) } group = \u0026#34;com.exemplo\u0026#34; kotlin { jvmToolchain(17) } tasks.test { useJUnitPlatform() } dependencies { testImplementation(\u0026#34;org.junit.jupiter:junit-jupiter:5.10.1\u0026#34;) testImplementation(\u0026#34;io.mockk:mockk:1.13.9\u0026#34;) } // Uso em qualquer modulo // core/domain/build.gradle.kts plugins { id(\u0026#34;kotlin-library-conventions\u0026#34;) } dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3\u0026#34;) } Tasks Customizadas O Gradle permite criar tasks personalizadas em Kotlin:\n// Task simples tasks.register(\u0026#34;limparLogs\u0026#34;) { group = \u0026#34;manutencao\u0026#34; description = \u0026#34;Remove arquivos de log antigos\u0026#34; doLast { val logDir = file(\u0026#34;logs\u0026#34;) if (logDir.exists()) { logDir.listFiles() ?.filter { it.extension == \u0026#34;log\u0026#34; } ?.forEach { it.delete() } println(\u0026#34;Logs removidos com sucesso\u0026#34;) } } } // Task tipada com inputs e outputs abstract class GerarRelatorioTask : DefaultTask() { @get:InputDirectory abstract val sourceDir: DirectoryProperty @get:OutputFile abstract val reportFile: RegularFileProperty @TaskAction fun gerar() { val fontes = sourceDir.get().asFile.walkTopDown() .filter { it.extension == \u0026#34;kt\u0026#34; } .toList() val relatorio = buildString { appendLine(\u0026#34;Relatorio do Projeto\u0026#34;) appendLine(\u0026#34;Total de arquivos Kotlin: ${fontes.size}\u0026#34;) appendLine(\u0026#34;Total de linhas: ${fontes.sumOf { it.readLines().size }}\u0026#34;) } reportFile.get().asFile.writeText(relatorio) } } tasks.register\u0026lt;GerarRelatorioTask\u0026gt;(\u0026#34;gerarRelatorio\u0026#34;) { sourceDir.set(file(\u0026#34;src/main/kotlin\u0026#34;)) reportFile.set(file(\u0026#34;build/relatorio.txt\u0026#34;)) } Configuração para Android Projetos Android possuem configurações específicas:\n// build.gradle.kts (app) plugins { id(\u0026#34;com.android.application\u0026#34;) kotlin(\u0026#34;android\u0026#34;) kotlin(\u0026#34;plugin.serialization\u0026#34;) id(\u0026#34;com.google.dagger.hilt.android\u0026#34;) kotlin(\u0026#34;kapt\u0026#34;) } android { namespace = \u0026#34;com.exemplo.app\u0026#34; compileSdk = 34 defaultConfig { applicationId = \u0026#34;com.exemplo.app\u0026#34; minSdk = 24 targetSdk = 34 versionCode = 1 versionName = \u0026#34;1.0.0\u0026#34; testInstrumentationRunner = \u0026#34;androidx.test.runner.AndroidJUnitRunner\u0026#34; } buildTypes { release { isMinifyEnabled = true proguardFiles( getDefaultProguardFile(\u0026#34;proguard-android-optimize.txt\u0026#34;), \u0026#34;proguard-rules.pro\u0026#34; ) } debug { isDebuggable = true applicationIdSuffix = \u0026#34;.debug\u0026#34; } } buildFeatures { compose = true buildConfig = true } composeOptions { kotlinCompilerExtensionVersion = \u0026#34;1.5.8\u0026#34; } kotlinOptions { jvmTarget = \u0026#34;17\u0026#34; } } Otimização de Performance do Build Builds lentos prejudicam a produtividade. Configure o gradle.properties para otimizar:\n// gradle.properties org.gradle.jvmargs=-Xmx4g -XX:+UseParallelGC org.gradle.parallel=true org.gradle.caching=true org.gradle.configuration-cache=true kotlin.incremental=true kotlin.caching.enabled=true // Para projetos Android android.useAndroidX=true android.nonTransitiveRClass=true Boas Práticas com Gradle e Kotlin Use Kotlin DSL: migre de Groovy para Kotlin DSL para obter type safety e autocomplete. Centralize versões com Version Catalogs: elimina inconsistencias de versões entre modulos. Crie convention plugins: evita duplicacao de configuração em projetos multi-modulo. Configure cache e builds paralelos: melhora significativamente o tempo de build. Minimize dependências transitivas: use implementation em vez de api quando a dependência não precisa ser exposta ao consumidor. Atualize o Gradle regularmente: cada versão traz melhorias de performance e novos recursos. Use buildSrc ou composite builds: para lógica de build complexa e compartilhada. Erros Comuns e Armadilhas Confundir implementation e api: api expõe a dependência aos consumidores do modulo, aumentando o tempo de compilação. Use implementation por padrão. Nao configurar cache: sem cache, builds incrementais não aproveitam resultados anteriores. Version conflicts: dependências transitivas podem trazer versões incompativeis. Use resolutionStrategy ou constraints para resolver. buildSrc invalida todo o cache: qualquer mudanca no buildSrc recompila todo o projeto. Para projetos grandes, prefira composite builds. Ignorar warnings de depreciacao: warnings no Gradle frequentemente antecedem breaking changes em versões futuras. Resolva-os proativamente. Conclusão e Próximos Passos Dominar o Gradle e tao importante quanto dominar a linguagem Kotlin em si. Uma configuração de build bem estruturada acelera o desenvolvimento, facilita a colaboracao e prepara o projeto para CI/CD. Explore nossos guias sobre CI/CD e Docker para integrar o Gradle em pipelines de deploy automatizado e leve a automação do seu projeto ao proximo nível.\n","permalink":"https://kotlin.dev.br/guias/guia-kotlin-gradle/","summary":"\u003cp\u003eO Gradle é o sistema de build padrão para projetos Kotlin, tanto no Android quanto no backend. Com a adoção do Kotlin DSL nos scripts de build (\u003ccode\u003ebuild.gradle.kts\u003c/code\u003e em vez de \u003ccode\u003ebuild.gradle\u003c/code\u003e), a configuração ganha autocomplete, type safety e toda a expressividade do Kotlin. Compreender o Gradle profundamente e essencial para qualquer desenvolvedor Kotlin, pois ele controla compilação, dependências, testes, empacotamento e publicacao. Neste guia, vamos desde a estrutura básica até configurações avançadas com version catalogs, convention plugins e otimização de performance de build.\u003c/p\u003e","title":"Kotlin com Gradle: Guia Completo em Português | Kotlin Brasil"},{"content":"Testes unitários são a base de qualquer projeto profissional em Kotlin. Neste tutorial, vamos aprender a escrever testes eficazes usando JUnit 5 e MockK, desde a configuração inicial até técnicas avançadas como testes parametrizados e testes de coroutines. Se você quer entregar código com confiança, este guia é para você.\nPor que Testar? Testes unitários verificam se unidades individuais do seu código (funções, classes, métodos) funcionam corretamente de forma isolada. Eles oferecem feedback rápido durante o desenvolvimento, documentam o comportamento esperado do sistema e protegem contra regressões quando você refatora ou adiciona novas features. Em Kotlin, a expressividade da linguagem torna os testes especialmente legíveis e concisos.\nPasso 1: Configuração do Projeto com JUnit 5 Primeiro, configure as dependências no build.gradle.kts:\n// build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.0.0\u0026#34; } dependencies { testImplementation(kotlin(\u0026#34;test\u0026#34;)) testImplementation(\u0026#34;org.junit.jupiter:junit-jupiter:5.10.3\u0026#34;) testImplementation(\u0026#34;io.mockk:mockk:1.13.12\u0026#34;) testImplementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1\u0026#34;) } tasks.test { useJUnitPlatform() } Com kotlin(\u0026quot;test\u0026quot;), o Kotlin já inclui as assertions básicas. O JUnit 5 serve como engine de execução, e o MockK é a biblioteca de mocking idiomática para Kotlin.\nPasso 2: Escrevendo seu Primeiro Teste Vamos começar com uma classe simples e seus testes correspondentes:\n// src/main/kotlin/Calculadora.kt class Calculadora { fun somar(a: Int, b: Int): Int = a + b fun dividir(a: Double, b: Double): Double { require(b != 0.0) { \u0026#34;Divisor nao pode ser zero\u0026#34; } return a / b } fun ehPar(numero: Int): Boolean = numero % 2 == 0 } Agora, o teste:\n// src/test/kotlin/CalculadoraTest.kt import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import kotlin.test.assertEquals import kotlin.test.assertTrue import kotlin.test.assertFalse class CalculadoraTest { private val calc = Calculadora() @Test fun `deve somar dois numeros corretamente`() { assertEquals(5, calc.somar(2, 3)) assertEquals(0, calc.somar(-1, 1)) assertEquals(-4, calc.somar(-2, -2)) } @Test fun `deve dividir dois numeros`() { assertEquals(2.5, calc.dividir(5.0, 2.0)) } @Test fun `deve lancar excecao ao dividir por zero`() { assertThrows\u0026lt;IllegalArgumentException\u0026gt; { calc.dividir(10.0, 0.0) } } @Test fun `deve verificar se numero eh par`() { assertTrue(calc.ehPar(4)) assertFalse(calc.ehPar(7)) } } Note que Kotlin permite nomes de testes com espaços usando backticks, o que melhora enormemente a legibilidade dos relatórios de testes. Adote essa prática para descrever o comportamento esperado de forma clara.\nPasso 3: Ciclo de Vida dos Testes O JUnit 5 oferece annotations para controlar o ciclo de vida dos testes. Use @BeforeEach para configurar estado antes de cada teste e @AfterEach para limpeza:\nimport org.junit.jupiter.api.* class RepositorioUsuariosTest { private lateinit var repositorio: RepositorioUsuarios @BeforeEach fun configurar() { repositorio = RepositorioUsuarios() repositorio.adicionar(Usuario(1, \u0026#34;Ana\u0026#34;, \u0026#34;ana@email.com\u0026#34;)) } @AfterEach fun limpar() { repositorio.limparTodos() } @Test fun `deve encontrar usuario por id`() { val usuario = repositorio.buscarPorId(1) assertEquals(\u0026#34;Ana\u0026#34;, usuario?.nome) } @Test fun `deve retornar null para id inexistente`() { val usuario = repositorio.buscarPorId(999) assertNull(usuario) } companion object { @JvmStatic @BeforeAll fun inicializacao() { println(\u0026#34;Executado uma vez antes de todos os testes\u0026#34;) } } } O @BeforeAll é útil para inicializações pesadas como conexão com banco de dados de teste. Note o uso de companion object com @JvmStatic, exigido pelo JUnit 5 para métodos estáticos.\nPasso 4: Mocking com MockK O MockK é a biblioteca de mocking mais popular para Kotlin. Diferente do Mockito, ele foi criado especificamente para Kotlin e suporta nativamente coroutines, extension functions e data classes.\nimport io.mockk.* import org.junit.jupiter.api.Test import kotlin.test.assertEquals interface ServicoEmail { fun enviar(destinatario: String, assunto: String, corpo: String): Boolean } class ServicoNotificacao(private val email: ServicoEmail) { fun notificarUsuario(usuario: Usuario, mensagem: String): Boolean { return email.enviar(usuario.email, \u0026#34;Notificação\u0026#34;, mensagem) } } class ServicoNotificacaoTest { private val emailMock = mockk\u0026lt;ServicoEmail\u0026gt;() private val serviço = ServicoNotificacao(emailMock) @Test fun `deve enviar email para o usuario`() { every { emailMock.enviar(any(), any(), any()) } returns true val resultado = serviço.notificarUsuario( Usuario(1, \u0026#34;Carlos\u0026#34;, \u0026#34;carlos@email.com\u0026#34;), \u0026#34;Sua conta foi ativada\u0026#34; ) assertTrue(resultado) verify { emailMock.enviar(\u0026#34;carlos@email.com\u0026#34;, \u0026#34;Notificação\u0026#34;, \u0026#34;Sua conta foi ativada\u0026#34;) } } @Test fun `deve retornar false quando envio falhar`() { every { emailMock.enviar(any(), any(), any()) } returns false val resultado = serviço.notificarUsuario( Usuario(1, \u0026#34;Ana\u0026#34;, \u0026#34;ana@email.com\u0026#34;), \u0026#34;Teste\u0026#34; ) assertFalse(resultado) } } O every { ... } returns ... define o comportamento do mock, e verify { ... } confirma que o método foi chamado com os argumentos corretos. O any() é um matcher que aceita qualquer valor.\nPasso 5: Testando Coroutines com runTest Para testar funções suspend, use o runTest do módulo kotlinx-coroutines-test. Ele controla o tempo virtual, permitindo testar delays sem esperar o tempo real.\nimport kotlinx.coroutines.test.runTest import kotlinx.coroutines.delay import io.mockk.coEvery import io.mockk.coVerify interface RepositorioRemoto { suspend fun buscarDados(id: String): String } class CasoDeUso(private val repositorio: RepositorioRemoto) { suspend fun executar(id: String): Result\u0026lt;String\u0026gt; { return try { val dados = repositorio.buscarDados(id) Result.success(dados) } catch (e: Exception) { Result.failure(e) } } } class CasoDeUsoTest { private val repoMock = mockk\u0026lt;RepositorioRemoto\u0026gt;() private val casoDeUso = CasoDeUso(repoMock) @Test fun `deve retornar sucesso quando repositorio responde`() = runTest { coEvery { repoMock.buscarDados(\u0026#34;123\u0026#34;) } returns \u0026#34;dados-do-servidor\u0026#34; val resultado = casoDeUso.executar(\u0026#34;123\u0026#34;) assertTrue(resultado.isSuccess) assertEquals(\u0026#34;dados-do-servidor\u0026#34;, resultado.getOrNull()) coVerify { repoMock.buscarDados(\u0026#34;123\u0026#34;) } } @Test fun `deve retornar falha quando repositorio lanca excecao`() = runTest { coEvery { repoMock.buscarDados(any()) } throws RuntimeException(\u0026#34;Erro de rede\u0026#34;) val resultado = casoDeUso.executar(\u0026#34;456\u0026#34;) assertTrue(resultado.isFailure) } } Note o uso de coEvery e coVerify (prefixo co) para funções suspend. O runTest avança automaticamente o tempo virtual quando encontra chamadas a delay, então seus testes executam instantaneamente.\nPasso 6: Testes Parametrizados Testes parametrizados permitem executar o mesmo teste com diferentes entradas, reduzindo duplicação:\nimport org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.CsvSource import org.junit.jupiter.params.provider.MethodSource import java.util.stream.Stream class ValidadorTest { @ParameterizedTest @CsvSource( \u0026#34;teste@email.com, true\u0026#34;, \u0026#34;invalido, false\u0026#34;, \u0026#34;user@domain.org, true\u0026#34;, \u0026#34;\u0026#39;\u0026#39;, false\u0026#34;, \u0026#34;sem-arroba.com, false\u0026#34; ) fun `deve validar formato de email`(email: String, esperado: Boolean) { val validador = ValidadorEmail() assertEquals(esperado, validador.ehValido(email)) } @ParameterizedTest @MethodSource(\u0026#34;fornecerSenhas\u0026#34;) fun `deve validar forca da senha`(caso: CasoSenha) { val validador = ValidadorSenha() assertEquals(caso.esperado, validador.ehForte(caso.senha)) } companion object { @JvmStatic fun fornecerSenhas(): Stream\u0026lt;CasoSenha\u0026gt; = Stream.of( CasoSenha(\u0026#34;123\u0026#34;, false), CasoSenha(\u0026#34;Abc@1234\u0026#34;, true), CasoSenha(\u0026#34;senhafraca\u0026#34;, false), CasoSenha(\u0026#34;F0rte!Senh@\u0026#34;, true) ) } data class CasoSenha(val senha: String, val esperado: Boolean) } O @CsvSource é prático para dados simples. Para casos mais complexos, use @MethodSource com um método que retorna um Stream de objetos.\nBoas Práticas para Código Testável Escrever testes eficientes começa com código bem estruturado. Aplique injeção de dependências — receba dependências via construtor ao invés de criá-las internamente. Use interfaces para definir contratos que podem ser facilmente mockados. Mantenha funções pequenas e com responsabilidade única. Evite estado global e efeitos colaterais ocultos.\nSiga o padrão AAA (Arrange, Act, Assert): configure o cenário, execute a ação e verifique o resultado. Cada teste deve ser independente e não depender da ordem de execução.\nErros Comuns 1. Testes que dependem uns dos outros: Cada teste deve configurar seu próprio estado. Nunca assuma que um teste rodou antes de outro. Use @BeforeEach para garantir estado limpo.\n2. Testar implementação ao invés de comportamento: Evite verificar detalhes internos como quantas vezes um método privado foi chamado. Teste o resultado observável — a saída da função, o estado final do objeto.\n3. Mocks excessivos: Se você precisa de muitos mocks em um teste, provavelmente o código tem acoplamento alto. Refatore para reduzir dependências antes de adicionar mais mocks.\n4. Não testar cenários de erro: Teste não apenas o caminho feliz. Verifique exceções, valores nulos, listas vazias e entradas inválidas.\n5. Esquecer coEvery para suspend functions: Usar every ao invés de coEvery com funções suspend causa erros confusos em tempo de execução. Sempre use a variante co para coroutines.\nConclusão e Próximos Passos Neste tutorial, cobrimos o ecossistema completo de testes unitários em Kotlin: JUnit 5 para estrutura e asserções, MockK para mocking idiomático, runTest para coroutines e testes parametrizados para reduzir duplicação. Com essas ferramentas, você tem tudo que precisa para criar uma suíte de testes robusta e confiável.\nComo próximos passos, explore testes de integração com TestContainers para bancos de dados, testes de API com o módulo de testes do Ktor, e ferramentas de cobertura de código como JaCoCo. Confira também nosso tutorial sobre Coroutines Avançadas para entender melhor o runTest e padrões avançados de concorrência testável. Frameworks de teste modernos existem em todos os ecossistemas — Python conta com pytest para testes elegantes e Go possui testing nativo na biblioteca padrão.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-testes-unitarios/","summary":"\u003cp\u003eTestes unitários são a base de qualquer projeto profissional em Kotlin. Neste tutorial, vamos aprender a escrever testes eficazes usando \u003cstrong\u003eJUnit 5\u003c/strong\u003e e \u003cstrong\u003eMockK\u003c/strong\u003e, desde a configuração inicial até técnicas avançadas como testes parametrizados e testes de \u003ca href=\"/glossario/coroutine/\"\u003ecoroutines\u003c/a\u003e. Se você quer entregar código com confiança, este guia é para você.\u003c/p\u003e\n\u003ch2 id=\"por-que-testar\"\u003ePor que Testar?\u003c/h2\u003e\n\u003cp\u003eTestes unitários verificam se unidades individuais do seu código (funções, \u003ca href=\"/glossario/class/\"\u003eclasses\u003c/a\u003e, métodos) funcionam corretamente de forma isolada. Eles oferecem feedback rápido durante o desenvolvimento, documentam o comportamento esperado do sistema e protegem contra regressões quando você refatora ou adiciona novas features. Em Kotlin, a expressividade da linguagem torna os testes especialmente legíveis e concisos.\u003c/p\u003e","title":"Testes Unitários em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Injeção de dependência (DI) é um padrão fundamental no desenvolvimento de software que promove baixo acoplamento, alta testabilidade e código mais fácil de manter. Em vez de uma classe criar suas proprias dependências, elas são fornecidas externamente, permitindo trocar implementacoes sem alterar o código consumidor. No ecossistema Kotlin, duas solucoes se destacam: Koin, um framework leve baseado em DSL Kotlin, e Hilt, a solução oficial do Google baseada no Dagger. Neste guia, exploraremos ambas as abordagens com exemplos práticos, comparações e cenários de uso recomendados.\nPor Que Usar Injeção de Dependencia Sem DI, classes criam suas dependências internamente, criando acoplamento forte:\n// Sem DI - Acoplado e dificil de testar class PedidoService { private val repository = PedidoRepositoryImpl( ApiClient(), // Dependencia interna DatabaseHelper.getInstance() // Singleton global ) fun criarPedido(request: PedidoRequest): Pedido { return repository.salvar(request.toPedido()) } } // Com DI - Desacoplado e testavel class PedidoService( private val repository: PedidoRepository // Interface injetada ) { fun criarPedido(request: PedidoRequest): Pedido { return repository.salvar(request.toPedido()) } } Com DI, podemos facilmente substituir PedidoRepository por um mock em testes ou trocar a implementação real sem alterar PedidoService.\nKoin: Injeção de Dependencia com DSL Kotlin O Koin e um framework de DI leve que usa DSL Kotlin em vez de geracao de código ou anotações. E popular por sua simplicidade e integração natural com Kotlin.\nConfiguração // build.gradle.kts dependencies { // Koin Core implementation(\u0026#34;io.insert-koin:koin-core:3.5.3\u0026#34;) // Koin Android implementation(\u0026#34;io.insert-koin:koin-android:3.5.3\u0026#34;) // Koin Compose (opcional) implementation(\u0026#34;io.insert-koin:koin-androidx-compose:3.5.3\u0026#34;) // Koin Test testImplementation(\u0026#34;io.insert-koin:koin-test-junit5:3.5.3\u0026#34;) } Definindo Modulos val networkModule = module { single { HttpClient { install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true }) } } } single\u0026lt;ProdutoApiService\u0026gt; { ProdutoApiServiceImpl(get()) } } val databaseModule = module { single { Room.databaseBuilder( androidContext(), AppDatabase::class.java, \u0026#34;meu_app_db\u0026#34; ).build() } single { get\u0026lt;AppDatabase\u0026gt;().produtoDao() } single { get\u0026lt;AppDatabase\u0026gt;().pedidoDao() } } val repositoryModule = module { single\u0026lt;ProdutoRepository\u0026gt; { ProdutoRepositoryImpl( apiService = get(), produtoDao = get() ) } single\u0026lt;PedidoRepository\u0026gt; { PedidoRepositoryImpl( apiService = get(), pedidoDao = get() ) } } val useCaseModule = module { factory { CriarPedidoUseCase(get(), get()) } factory { ListarProdutosUseCase(get()) } factory { CancelarPedidoUseCase(get()) } } val viewModelModule = module { viewModel { ProdutoViewModel(get()) } viewModel { PedidoViewModel(get(), get(), get()) } viewModel { (pedidoId: Long) -\u0026gt; DetalhePedidoViewModel(pedidoId, get()) } } A diferenca entre single e factory e crucial: single cria uma única instancia (singleton), enquanto factory cria uma nova instancia a cada injeção. Use viewModel para ViewModels do Android.\nIniciando o Koin class MeuApp : Application() { override fun onCreate() { super.onCreate() startKoin { androidLogger(Level.DEBUG) androidContext(this@MeuApp) modules( networkModule, databaseModule, repositoryModule, useCaseModule, viewModelModule ) } } } Usando Injeção no Código // Em Activities e Fragments class ProdutoFragment : Fragment() { private val viewModel: ProdutoViewModel by viewModel() private val logger: Logger by inject() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.carregarProdutos() } } // Em Jetpack Compose @Composable fun TelaProdutos( viewModel: ProdutoViewModel = koinViewModel() ) { val estado by viewModel.uiState.collectAsStateWithLifecycle() // Renderizar UI } // Em classes comuns (nao Android) class MeuServico : KoinComponent { private val repository: ProdutoRepository by inject() } Hilt: Injeção de Dependencia Oficial do Google O Hilt e construido sobre o Dagger e oferece integração profunda com componentes Android. Usa geracao de código em tempo de compilação, resultando em melhor performance em runtime.\nConfiguração // build.gradle.kts (projeto) plugins { id(\u0026#34;com.google.dagger.hilt.android\u0026#34;) version \u0026#34;2.50\u0026#34; apply false } // build.gradle.kts (app) plugins { id(\u0026#34;com.google.dagger.hilt.android\u0026#34;) kotlin(\u0026#34;kapt\u0026#34;) } dependencies { implementation(\u0026#34;com.google.dagger:hilt-android:2.50\u0026#34;) kapt(\u0026#34;com.google.dagger:hilt-android-compiler:2.50\u0026#34;) implementation(\u0026#34;androidx.hilt:hilt-navigation-compose:1.1.0\u0026#34;) testImplementation(\u0026#34;com.google.dagger:hilt-android-testing:2.50\u0026#34;) kaptTest(\u0026#34;com.google.dagger:hilt-android-compiler:2.50\u0026#34;) } Definindo Modulos Hilt @Module @InstallIn(SingletonComponent::class) object NetworkModule { @Provides @Singleton fun provideHttpClient(): HttpClient { return HttpClient { install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true }) } } } @Provides @Singleton fun provideApiService(httpClient: HttpClient): ProdutoApiService { return ProdutoApiServiceImpl(httpClient) } } @Module @InstallIn(SingletonComponent::class) object DatabaseModule { @Provides @Singleton fun provideDatabase(@ApplicationContext context: Context): AppDatabase { return Room.databaseBuilder( context, AppDatabase::class.java, \u0026#34;meu_app_db\u0026#34; ).build() } @Provides fun provideProdutoDao(database: AppDatabase): ProdutoDao { return database.produtoDao() } } @Module @InstallIn(SingletonComponent::class) abstract class RepositoryModule { @Binds @Singleton abstract fun bindProdutoRepository( impl: ProdutoRepositoryImpl ): ProdutoRepository @Binds @Singleton abstract fun bindPedidoRepository( impl: PedidoRepositoryImpl ): PedidoRepository } Usando Injeção com Hilt @HiltAndroidApp class MeuApp : Application() @AndroidEntryPoint class ProdutoFragment : Fragment() { private val viewModel: ProdutoViewModel by viewModels() } @HiltViewModel class ProdutoViewModel @Inject constructor( private val listarProdutos: ListarProdutosUseCase ) : ViewModel() { private val _uiState = MutableStateFlow\u0026lt;UiState\u0026gt;(UiState.Loading) val uiState: StateFlow\u0026lt;UiState\u0026gt; = _uiState.asStateFlow() init { carregarProdutos() } fun carregarProdutos() { viewModelScope.launch { listarProdutos() .onSuccess { _uiState.value = UiState.Success(it) } .onFailure { _uiState.value = UiState.Error(it.message ?: \u0026#34;\u0026#34;) } } } } // Em Compose @Composable fun TelaProdutos( viewModel: ProdutoViewModel = hiltViewModel() ) { val estado by viewModel.uiState.collectAsStateWithLifecycle() // Renderizar UI } Koin vs Hilt: Quando Usar Cada Um O Koin e ideal para projetos que valorizam simplicidade, configuração rápida e suporte a Kotlin Multiplatform. Sua DSL e intuitiva e não requer geracao de código. Porem, erros de configuração só são detectados em runtime.\nO Hilt oferece verificação em tempo de compilação, melhor performance em aplicações grandes e integração profunda com o ecossistema Android. No entanto, exige mais configuração e o uso de kapt ou ksp, que pode aumentar o tempo de build.\nPara projetos Android puros de grande escala, o Hilt e geralmente a melhor escolha. Para projetos menores, backend com Ktor ou Kotlin Multiplatform, o Koin tende a ser mais adequado.\nBoas Práticas para Injeção de Dependencia Injete interfaces, não implementacoes: isso permite trocar implementacoes facilmente, especialmente em testes. Use constructor injection: prefira injetar pelo construtor em vez de field injection. E mais explicito e testavel. Organize modulos por feature ou camada: modulos pequenos e focados são mais faceis de manter. Evite Service Locator quando possível: embora Koin permita by inject() em qualquer lugar, prefira constructor injection na maioria dos casos. Defina escopos corretamente: singletons consomem memória durante toda a vida da aplicação. Use factory ou escopos mais restritos quando a instancia não precisa ser compartilhada. Teste a configuração de DI: o Koin oferece checkModules() para verificar se todos os modulos estao configurados corretamente. Erros Comuns e Armadilhas Dependências circulares: A depende de B e B depende de A. Refatore extraindo uma interface ou um terceiro componente. Singleton quando deveria ser factory: usar singleton para objetos com estado mutavel pode causar bugs de concorrência. Esquecer anotações no Hilt: cada Activity, Fragment é ViewModel que usa injeção precisa das anotações corretas (@AndroidEntryPoint, @HiltViewModel). Modulos Koin não registrados: adicionar um modulo e esquecer de inclui-lo no startKoin resulta em erros de runtime. Over-engineering: para projetos muito simples, DI manual (passando dependências pelo construtor) pode ser suficiente sem framework nenhum. Conclusão e Próximos Passos A injeção de dependência e um pilar da arquitetura de software moderna. Tanto Koin quanto Hilt oferecem solucoes robustas para Kotlin, cada uma com suas vantagens. Escolha a que melhor se adapta ao seu projeto e equipe. Para ir além, explore como DI se integra com Clean Architecture, consulte nossos guias sobre testes para aprender a usar mocks com DI e estude modulos avançados como Work Manager injection e Navigation injection. Se você trabalha com outras linguagens, Python também possui frameworks de DI robustos, e Go adota uma abordagem mais explícita de injeção via construtor.\n","permalink":"https://kotlin.dev.br/guias/guia-dependency-injection-kotlin/","summary":"\u003cp\u003eInjeção de dependência (DI) é um padrão fundamental no desenvolvimento de software que promove baixo acoplamento, alta testabilidade e código mais fácil de manter. Em vez de uma classe criar suas proprias dependências, elas são fornecidas externamente, permitindo trocar implementacoes sem alterar o código consumidor. No ecossistema Kotlin, duas solucoes se destacam: Koin, um framework leve baseado em DSL Kotlin, e Hilt, a solução oficial do Google baseada no Dagger. Neste guia, exploraremos ambas as abordagens com exemplos práticos, comparações e cenários de uso recomendados.\u003c/p\u003e","title":"Injeção de Dependencia em Kotlin: Guia Completo com Koin e Hilt | Kotlin Brasil"},{"content":"Inteligencia artificial e machine learning estao transformando o desenvolvimento de software, e Kotlin esta se posicionando como uma linguagem cada vez mais relevante nesse espaco. Embora Python ainda domine o treinamento de modelos, Kotlin brilha na integração, deploy e construcao de aplicações inteligentes. Vamos explorar como usar Kotlin no mundo da IA.\nKotlin e IA: Onde se Encaixam O papel do Kotlin no ecossistema de IA não e substituir Python no treinamento de modelos. E usar a robustez, performance e segurança de tipos do Kotlin para construir aplicações que consomem e orquestram modelos de IA. E nesse papel, Kotlin e excepcional.\nPense assim: Python treina o modelo, Kotlin coloca ele em producao com segurança e escala.\nIntegração com LLMs Uma das areas mais quentes é a integração com Large Language Models. Bibliotecas como LangChain4j e Spring AI tornam isso simples em Kotlin:\n// Integração com OpenAI usando LangChain4j class AssistenteService( private val chatModel: ChatLanguageModel, private val embeddingStore: EmbeddingStore\u0026lt;TextSegment\u0026gt;, private val embeddingModel: EmbeddingModel ) { suspend fun responderPergunta( pergunta: String, contexto: String? = null ): String { // RAG - Retrieval Augmented Generation val embedding = embeddingModel.embed(pergunta).content() val relevantes = embeddingStore.findRelevant(embedding, 5) val contextoAdicional = relevantes.joinToString(\u0026#34;\\n\u0026#34;) { it.embedded().text() } val prompt = buildString { appendLine(\u0026#34;Você e um assistente técnico sobre Kotlin.\u0026#34;) appendLine(\u0026#34;Use o seguinte contexto para responder:\u0026#34;) appendLine(contextoAdicional) if (contexto != null) appendLine(\u0026#34;Contexto adicional: $contexto\u0026#34;) appendLine(\u0026#34;Pergunta: $pergunta\u0026#34;) } return withContext(Dispatchers.IO) { chatModel.generate(prompt) } } } Spring AI com Kotlin Spring AI oferece uma integração elegante para construir aplicações com IA:\n@RestController @RequestMapping(\u0026#34;/api/assistente\u0026#34;) class AssistenteController( private val chatClient: ChatClient, private val vectorStore: VectorStore ) { @PostMapping(\u0026#34;/chat\u0026#34;) suspend fun chat(@RequestBody request: ChatRequest): ChatResponse { // Buscar documentos relevantes val documentos = vectorStore.similaritySearch( SearchRequest.query(request.mensagem) .withTopK(5) .withSimilarityThreshold(0.7) ) val contexto = documentos.joinToString(\u0026#34;\\n\u0026#34;) { it.content } val resposta = chatClient.prompt() .system(\u0026#34;Você e um especialista em Kotlin. Use o contexto fornecido.\u0026#34;) .user(\u0026#34;\u0026#34;\u0026#34; Contexto: $contexto Pergunta: ${request.mensagem} \u0026#34;\u0026#34;\u0026#34;.trimIndent()) .call() .content() return ChatResponse( mensagem = resposta, fontes = documentos.map { it.metadata[\u0026#34;source\u0026#34;] as String } ) } } Machine Learning com Kotlin KotlinDL KotlinDL e a biblioteca de deep learning nativa para Kotlin, desenvolvida pela JetBrains:\n// KotlinDL - Rede neural para classificacao de imagens val model = Sequential.of( Input(28, 28, 1), Conv2D(32, kernelSize = intArrayOf(3, 3), activation = Activations.Relu), MaxPool2D(poolSize = intArrayOf(2, 2)), Conv2D(64, kernelSize = intArrayOf(3, 3), activation = Activations.Relu), MaxPool2D(poolSize = intArrayOf(2, 2)), Flatten(), Dense(128, activation = Activations.Relu), Dense(10, activation = Activations.Softmax) ) model.use { it.compile( optimizer = Adam(), loss = Losses.SOFT_MAX_CROSS_ENTROPY_WITH_LOGITS, metric = Metrics.ACCURACY ) it.fit( dataset = trainDataset, epochs = 10, batchSize = 32 ) val accuracy = it.evaluate(testDataset).metrics[Metrics.ACCURACY] println(\u0026#34;Acuracia: $accuracy\u0026#34;) } Smile com Kotlin Smile e uma biblioteca ML abrangente para a JVM que funciona perfeitamente com Kotlin:\n// Smile - Machine Learning classico import smile.classification.randomForest import smile.data.formula.Formula fun treinarModelo(dados: DataFrame): RandomForest { val formula = Formula.lhs(\u0026#34;target\u0026#34;) val modelo = randomForest( formula = formula, data = dados, ntrees = 100, maxDepth = 10, nodeSize = 5 ) println(\u0026#34;OOB error: ${modelo.error()}\u0026#34;) return modelo } fun prever(modelo: RandomForest, novoDado: DoubleArray): Int { return modelo.predict(novoDado) } Processamento de Dados com Kotlin Antes de alimentar modelos de ML, você precisa processar dados. Kotlin tem ferramentas excelentes para isso:\n// Kotlin DataFrame - Manipulacao de dados import org.jetbrains.kotlinx.dataframe.api.* fun analisarVendas(dados: DataFrame\u0026lt;Venda\u0026gt;) { // Agrupamento e agregacao val porRegiao = dados .groupBy { região } .aggregate { count() into \u0026#34;total_vendas\u0026#34; mean { valor } into \u0026#34;ticket_medio\u0026#34; sum { valor } into \u0026#34;receita_total\u0026#34; max { valor } into \u0026#34;maior_venda\u0026#34; } .sortByDesc { \u0026#34;receita_total\u0026#34;\u0026lt;Double\u0026gt;() } // Filtragem e transformacao val vendasAltas = dados .filter { valor \u0026gt; 1000.0 \u0026amp;\u0026amp; status == \u0026#34;concluida\u0026#34; } .add(\u0026#34;comissao\u0026#34;) { valor * 0.05 } .select { nome and valor and comissao } println(porRegiao) println(vendasAltas) } Kandy para Visualização // Kandy - Visualização de dados nativa Kotlin import org.jetbrains.kotlinx.kandy.dsl.plot import org.jetbrains.kotlinx.kandy.letsplot.layers.* fun visualizarDistribuicao(dados: List\u0026lt;Double\u0026gt;) { val grafico = plot { histogram { x(dados) fillColor = Color.BLUE alpha = 0.7 } layout { title = \u0026#34;Distribuição de Valores\u0026#34; xAxisLabel = \u0026#34;Valor\u0026#34; yAxisLabel = \u0026#34;Frequencia\u0026#34; } } } Construindo APIs de IA com Kotlin O cenário mais comum e construir APIs que servem modelos de ML:\n// API para servir modelo de ML @RestController @RequestMapping(\u0026#34;/api/ml\u0026#34;) class PredictionController( private val modelService: ModelService ) { @PostMapping(\u0026#34;/predict\u0026#34;) suspend fun predict( @Valid @RequestBody request: PredictionRequest ): ResponseEntity\u0026lt;PredictionResponse\u0026gt; { val features = request.toFeatureVector() val prediction = modelService.predict(features) return ResponseEntity.ok( PredictionResponse( prediction = prediction.label, confidence = prediction.confidence, features = request.featureNames, modelVersion = modelService.currentVersion() ) ) } @PostMapping(\u0026#34;/batch-predict\u0026#34;) suspend fun batchPredict( @RequestBody requests: List\u0026lt;PredictionRequest\u0026gt; ): ResponseEntity\u0026lt;List\u0026lt;PredictionResponse\u0026gt;\u0026gt; { val results = coroutineScope { requests.map { request -\u0026gt; async { val features = request.toFeatureVector() modelService.predict(features) } }.awaitAll() } return ResponseEntity.ok(results.mapIndexed { index, prediction -\u0026gt; PredictionResponse( prediction = prediction.label, confidence = prediction.confidence, features = requests[index].featureNames, modelVersion = modelService.currentVersion() ) }) } } // Service que gerencia modelos class ModelService( private val modelRepository: ModelRepository ) { private var currentModel: MLModel? = null suspend fun predict(features: DoubleArray): Prediction { val model = currentModel ?: loadLatestModel() return withContext(Dispatchers.Default) { model.predict(features) } } suspend fun loadLatestModel(): MLModel { val model = modelRepository.getLatestModel() currentModel = model return model } fun currentVersion(): String { return currentModel?.version ?: \u0026#34;unknown\u0026#34; } } Kotlin para Pipelines de Dados Kotlin com coroutines e Flow e excelente para construir pipelines de processamento de dados:\n// Pipeline de dados com Flow fun processarPipelineML(): Flow\u0026lt;ProcessedBatch\u0026gt; { return dataSource.streamRawData() .buffer(capacity = 100) .map { rawData -\u0026gt; limparDados(rawData) } .filter { it.qualidade \u0026gt; 0.8 } .map { dados -\u0026gt; extrairFeatures(dados) } .chunked(32) // Agrupar em batches .map { batch -\u0026gt; withContext(Dispatchers.Default) { ProcessedBatch( features = batch.map { it.featureVector }, labels = batch.map { it.label }, metadata = BatchMetadata( size = batch.size, timestamp = Clock.System.now() ) ) } } .onEach { batch -\u0026gt; logger.info(\u0026#34;Batch processado: ${batch.metadata.size} registros\u0026#34;) } } Mercado e Oportunidades A intersecao de Kotlin e IA cria oportunidades unicas no mercado brasileiro:\nBackend Engineer com foco em IA: Construir APIs que servem modelos de ML usando Spring Boot ou Ktor ML Engineer com Kotlin: Criar pipelines de dados e deploy de modelos usando a JVM Fullstack com IA: Integrar LLMs em aplicações mobile e web com Kotlin Empresas brasileiras como Nubank, iFood e Stone já usam Kotlin extensivamente e estao investindo cada vez mais em IA. Profissionais que combinam Kotlin com conhecimento de IA estao em alta demanda.\nConclusão Kotlin pode não ser a primeira linguagem que vem a mente quando se fala em IA, mas seu papel no ecossistema e crucial e crescente. Da integração com LLMs ao deploy de modelos em producao, passando por processamento de dados e construcao de APIs inteligentes, Kotlin oferece as ferramentas e a robustez necessarias para construir aplicações de IA de nível profissional.\nSe você já e desenvolvedor Kotlin, adicionar conhecimentos de IA ao seu repertorio e um diferencial competitivo enorme. As ferramentas estao la, a demanda esta crescendo e as oportunidades são reais. Comece experimentando com LangChain4j ou Spring AI e veja como é natural integrar IA em aplicações Kotlin. Para o lado de treinamento e data science, vale investir em Python como linguagem complementar.\n","permalink":"https://kotlin.dev.br/blog/kotlin-ia-machine-learning/","summary":"\u003cp\u003eInteligencia artificial e machine learning estao transformando o desenvolvimento de software, e Kotlin esta se posicionando como uma linguagem cada vez mais relevante nesse espaco. Embora Python ainda domine o treinamento de modelos, Kotlin brilha na integração, deploy e construcao de aplicações inteligentes. Vamos explorar como usar Kotlin no mundo da IA.\u003c/p\u003e\n\u003ch2 id=\"kotlin-e-ia-onde-se-encaixam\"\u003eKotlin e IA: Onde se Encaixam\u003c/h2\u003e\n\u003cp\u003eO papel do Kotlin no ecossistema de IA não e substituir \u003ca href=\"https://python.dev.br/\" target=\"_blank\" rel=\"noopener\" onclick=\"umami.track('portfolio-site-click', { destination: 'python.dev.br' })\"\u003ePython no treinamento de modelos\u003c/a\u003e. E usar a robustez, performance e segurança de tipos do Kotlin para construir aplicações que consomem e orquestram modelos de IA. E nesse papel, Kotlin e excepcional.\u003c/p\u003e","title":"Kotlin para IA e Machine Learning: Guia Prático | Kotlin Brasil"},{"content":"Neste tutorial, vamos construir uma API REST completa usando o Ktor, o framework web assíncrono e leve criado pela JetBrains especificamente para Kotlin. Você vai aprender desde a configuração inicial do projeto até a integração com banco de dados usando Exposed, passando por routing, serialização JSON, autenticação e testes. Se você quer aprofundar a parte de persistência depois deste guia, veja também o tutorial de Kotlin com PostgreSQL no backend. Se você já tem familiaridade com funções e coroutines em Kotlin, está pronto para começar.\nO que é o Ktor? Ktor é um framework assíncrono para criar aplicações web e microsserviços em Kotlin. Diferente de frameworks como Spring Boot, o Ktor é minimalista por design — você adiciona apenas os recursos (chamados de plugins) que precisa. Ele é construído sobre coroutines, o que significa que cada requisição é tratada de forma não-bloqueante usando suspend functions.\nA arquitetura do Ktor é baseada em um pipeline de plugins que interceptam e processam requisições HTTP. Isso torna o framework extremamente flexível e performático, ideal para microsserviços e APIs de alta concorrência.\nPasso 1: Configuração do Projeto A forma mais rápida de iniciar um projeto Ktor é usando o gerador online em start.ktor.io ou configurando manualmente o build.gradle.kts. Vamos pelo caminho manual para entender cada dependência.\n// build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.0.0\u0026#34; id(\u0026#34;io.ktor.plugin\u0026#34;) version \u0026#34;2.3.12\u0026#34; kotlin(\u0026#34;plugin.serialization\u0026#34;) version \u0026#34;2.0.0\u0026#34; } group = \u0026#34;com.exemplo\u0026#34; version = \u0026#34;1.0.0\u0026#34; application { mainClass.set(\u0026#34;com.exemplo.ApplicationKt\u0026#34;) } dependencies { // Ktor Server implementation(\u0026#34;io.ktor:ktor-server-core-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-netty-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-content-negotiation-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-serialization-kotlinx-json-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-auth-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-auth-jwt-jvm\u0026#34;) // Exposed (ORM) implementation(\u0026#34;org.jetbrains.exposed:exposed-core:0.52.0\u0026#34;) implementation(\u0026#34;org.jetbrains.exposed:exposed-dao:0.52.0\u0026#34;) implementation(\u0026#34;org.jetbrains.exposed:exposed-jdbc:0.52.0\u0026#34;) implementation(\u0026#34;com.h2database:h2:2.2.224\u0026#34;) // Testes testImplementation(\u0026#34;io.ktor:ktor-server-tests-jvm\u0026#34;) testImplementation(\u0026#34;org.jetbrains.kotlin:kotlin-test-junit:2.0.0\u0026#34;) } Observe que usamos o servidor Netty como engine. O Ktor suporta múltiplas engines (CIO, Jetty, Tomcat), mas Netty é a escolha mais comum para produção.\nAtenção às versões do Exposed em 2026 Muita gente chega a este tutorial procurando exatamente a dependência org.jetbrains.exposed:exposed-core:0.52.0. Ela aparece em vários projetos Kotlin antigos porque foi uma versão popular antes da estabilização do Exposed, mas hoje ela não deve ser copiada automaticamente para um projeto novo. Use o bloco acima como ponto de partida didático e, antes de criar um projeto de produção, confira o guia atualizado do Exposed 1.0 com R2DBC e o tutorial completo de Exposed ORM.\nA regra prática é simples:\nse o projeto usa JDBC tradicional, mantenha exposed-core, exposed-dao, exposed-jdbc e um driver como PostgreSQL ou H2; se a API precisa de acesso não bloqueante ponta a ponta, avalie exposed-r2dbc junto com Ktor, coroutines e um driver R2DBC; se o código é legado e já está preso em 0.52.0, migre com testes, porque mudanças de pacote e comportamento podem aparecer ao subir para a linha 1.x; se você está aprendendo, priorize entender a modelagem de tabela, transações e repositórios antes de discutir micro-otimizações de versão. Para este tutorial, o fluxo continua com JDBC porque ele é mais direto para iniciantes e funciona bem com H2 local, PostgreSQL em produção e deploys simples. Depois que a API estiver estável, você pode trocar a camada de persistência por R2DBC ou aprofundar no guia de Kotlin para backend sem jogar fora o aprendizado de routing, serialização e testes.\nPasso 2: Criando o Servidor e Definindo Rotas O ponto de entrada da aplicação Ktor é a função embeddedServer. Dentro dela, configuramos plugins e definimos rotas usando a DSL de routing.\n// src/main/kotlin/com/exemplo/Application.kt package com.exemplo import io.ktor.server.application.* import io.ktor.server.engine.* import io.ktor.server.netty.* import io.ktor.server.routing.* import io.ktor.server.response.* import io.ktor.http.* fun main() { embeddedServer(Netty, port = 8080, host = \u0026#34;0.0.0.0\u0026#34;) { configurarRotas() }.start(wait = true) } fun Application.configurarRotas() { routing { get(\u0026#34;/\u0026#34;) { call.respondText(\u0026#34;Bem-vindo à API Kotlin Brasil!\u0026#34;, ContentType.Text.Plain) } route(\u0026#34;/api/v1\u0026#34;) { get(\u0026#34;/status\u0026#34;) { call.respondText(\u0026#34;OK\u0026#34;, ContentType.Text.Plain) } } } } A DSL de routing do Ktor utiliza lambdas com receiver, permitindo definir rotas de forma declarativa e organizada. Cada bloco get, post, put e delete recebe o caminho da rota e uma suspend function que trata a requisição.\nPasso 3: Serialização JSON com kotlinx.serialization Para trabalhar com JSON, precisamos instalar o plugin ContentNegotiation e configurar o serializador.\nimport io.ktor.server.application.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.Serializable @Serializable data class Tarefa( val id: Int, val titulo: String, val concluida: Boolean = false ) fun Application.configurarSerializacao() { install(ContentNegotiation) { json() } } Agora podemos criar endpoints que recebem e retornam objetos Kotlin automaticamente serializados como JSON. Veja como fica um CRUD básico de tarefas:\nimport io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* import io.ktor.http.* val tarefas = mutableListOf\u0026lt;Tarefa\u0026gt;() fun Application.rotasTarefas() { routing { route(\u0026#34;/api/tarefas\u0026#34;) { get { call.respond(tarefas) } get(\u0026#34;/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toIntOrNull() val tarefa = tarefas.find { it.id == id } if (tarefa != null) { call.respond(tarefa) } else { call.respond(HttpStatusCode.NotFound, mapOf(\u0026#34;erro\u0026#34; to \u0026#34;Tarefa nao encontrada\u0026#34;)) } } post { val tarefa = call.receive\u0026lt;Tarefa\u0026gt;() tarefas.add(tarefa) call.respond(HttpStatusCode.Created, tarefa) } delete(\u0026#34;/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toIntOrNull() val removida = tarefas.removeIf { it.id == id } if (removida) { call.respond(HttpStatusCode.NoContent) } else { call.respond(HttpStatusCode.NotFound) } } } } } Passo 4: Autenticação com JWT O Ktor fornece plugins de autenticação prontos para uso. Vamos configurar autenticação via JWT (JSON Web Token), uma das abordagens mais comuns em APIs REST.\nimport io.ktor.server.auth.* import io.ktor.server.auth.jwt.* import com.auth0.jwt.JWT import com.auth0.jwt.algorithms.Algorithm fun Application.configurarAutenticacao() { val secret = \u0026#34;meu-segredo-super-secreto\u0026#34; val issuer = \u0026#34;kotlin-brasil\u0026#34; val audience = \u0026#34;api-usuarios\u0026#34; install(Authentication) { jwt(\u0026#34;auth-jwt\u0026#34;) { realm = \u0026#34;Acesso à API\u0026#34; verifier( JWT.require(Algorithm.HMAC256(secret)) .withAudience(audience) .withIssuer(issuer) .build() ) validate { credential -\u0026gt; if (credential.payload.audience.contains(audience)) { JWTPrincipal(credential.payload) } else null } } } routing { authenticate(\u0026#34;auth-jwt\u0026#34;) { get(\u0026#34;/api/perfil\u0026#34;) { val principal = call.principal\u0026lt;JWTPrincipal\u0026gt;() val email = principal!!.payload.getClaim(\u0026#34;email\u0026#34;).asString() call.respond(mapOf(\u0026#34;email\u0026#34; to email)) } } } } Rotas protegidas ficam dentro do bloco authenticate, garantindo que apenas requisições com token válido serão processadas.\nPasso 5: Integração com Banco de Dados usando Exposed O Exposed é o ORM oficial da JetBrains para Kotlin. Ele oferece duas abordagens: DSL (estilo SQL) e DAO (estilo Active Record). Vamos usar a abordagem DSL.\nimport org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.transaction object Tarefas : Table(\u0026#34;tarefas\u0026#34;) { val id = integer(\u0026#34;id\u0026#34;).autoIncrement() val titulo = varchar(\u0026#34;titulo\u0026#34;, 255) val concluida = bool(\u0026#34;concluida\u0026#34;).default(false) override val primaryKey = PrimaryKey(id) } fun inicializarBanco() { Database.connect(\u0026#34;jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;\u0026#34;, driver = \u0026#34;org.h2.Driver\u0026#34;) transaction { SchemaUtils.create(Tarefas) } } fun listarTarefas(): List\u0026lt;Tarefa\u0026gt; = transaction { Tarefas.selectAll().map { Tarefa( id = it[Tarefas.id], titulo = it[Tarefas.titulo], concluida = it[Tarefas.concluida] ) } } fun inserirTarefa(tarefa: Tarefa): Int = transaction { Tarefas.insert { it[titulo] = tarefa.titulo it[concluida] = tarefa.concluida }[Tarefas.id] } Para integrar com o Ktor, chame inicializarBanco() no módulo da aplicação e substitua a lista em memória pelas funções do Exposed nas rotas.\nPasso 6: Testando a Aplicação Ktor O Ktor inclui um módulo de testes que permite simular requisições HTTP sem iniciar um servidor real, usando testApplication.\nimport io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* import io.ktor.server.testing.* import kotlin.test.* class TarefasTest { @Test fun `deve retornar status OK`() = testApplication { application { configurarSerializacao() configurarRotas() } client.get(\u0026#34;/api/v1/status\u0026#34;).apply { assertEquals(HttpStatusCode.OK, status) assertEquals(\u0026#34;OK\u0026#34;, bodyAsText()) } } @Test fun `deve criar tarefa via POST`() = testApplication { application { configurarSerializacao() rotasTarefas() } client.post(\u0026#34;/api/tarefas\u0026#34;) { contentType(ContentType.Application.Json) setBody(\u0026#34;\u0026#34;\u0026#34;{\u0026#34;id\u0026#34;: 1, \u0026#34;titulo\u0026#34;: \u0026#34;Estudar Ktor\u0026#34;, \u0026#34;concluida\u0026#34;: false}\u0026#34;\u0026#34;\u0026#34;) }.apply { assertEquals(HttpStatusCode.Created, status) } } } O testApplication cria um ambiente isolado onde você pode testar cada módulo da sua aplicação independentemente, sem necessidade de subir o servidor Netty.\nDeploy Básico Para gerar um JAR executável, configure o plugin ktor no Gradle e execute:\n// build.gradle.kts ktor { fatJar { archiveFileName.set(\u0026#34;app.jar\u0026#34;) } } Depois, basta rodar ./gradlew buildFatJar e executar com java -jar build/libs/app.jar. Para containerizar, crie um Dockerfile simples baseado em uma imagem JVM como eclipse-temurin:21-jre-alpine.\nErros Comuns 1. Esquecer de instalar o plugin ContentNegotiation: Sem ele, o Ktor não sabe serializar objetos para JSON e retorna erro 500. Sempre chame install(ContentNegotiation) { json() } antes de usar call.respond com data classes.\n2. Não tratar parâmetros nulos nas rotas: call.parameters[\u0026quot;id\u0026quot;] retorna nullable String?. Sempre use toIntOrNull() e trate o caso nulo para evitar exceções em runtime.\n3. Bloquear a thread principal com operações de banco: O Exposed usa JDBC, que é bloqueante. Em produção, envolva as chamadas em newSuspendedTransaction do módulo exposed-kotlin ou use withContext(Dispatchers.IO) para não bloquear as coroutines do Ktor.\n4. Não configurar CORS: Se sua API será consumida por um frontend em outro domínio, instale o plugin CORS do Ktor. Sem ele, o navegador bloqueará as requisições.\n5. JWT secret hardcoded no código: Nunca deixe secrets diretamente no código fonte. Use variáveis de ambiente com System.getenv(\u0026quot;JWT_SECRET\u0026quot;) ou arquivos de configuração do Ktor (application.conf).\nConclusão e Próximos Passos Neste tutorial, construímos uma API REST funcional com Ktor cobrindo os pilares fundamentais: routing, serialização, autenticação JWT, integração com banco de dados Exposed e testes automatizados. O Ktor é uma excelente escolha para quem quer construir backends em Kotlin puro, aproveitando ao máximo as coroutines e a expressividade da linguagem.\nComo próximos passos, recomendamos explorar o Ktor Client para fazer requisições HTTP a outros serviços, configurar WebSockets com Ktor para comunicação em tempo real, integrar com bancos de dados de produção como PostgreSQL e documentar os contratos HTTP. Se a API será consumida por frontend, app mobile ou outro serviço, siga o tutorial de OpenAPI e Swagger no Ktor para expor schemas, exemplos e códigos de erro de forma profissional. Você também pode estudar o uso de Koin ou Kodein para injeção de dependências, tornando sua aplicação mais modular e testável.\nFAQ rápido sobre Ktor, Exposed e dependências Posso usar org.jetbrains.exposed:exposed-core:0.52.0 em um projeto novo? Pode, mas não é a melhor escolha para um projeto novo em 2026. A versão 0.52.0 ainda aparece em exemplos, buscas e bases antigas, mas o ecossistema Exposed avançou. Para código novo, consulte a versão estável atual no Maven Central e leia o resumo do Exposed 1.0 antes de fixar dependências.\nKtor combina melhor com Exposed JDBC ou R2DBC? Para aprender e entregar uma API pequena, JDBC com HikariCP é o caminho mais simples. Para serviços com muitas conexões simultâneas, streaming ou uma arquitetura já reativa, R2DBC pode fazer sentido. A decisão não deve ser tomada só porque Ktor usa coroutines; o banco, o driver, o pool e a equipe também importam.\nPreciso de Spring Boot para usar Kotlin no backend? Não. Spring Boot é excelente para equipes que já vivem no ecossistema Spring, mas Ktor é mais leve, direto e Kotlin-first. Se você ainda está comparando frameworks, leia também Ktor vs Spring Boot e o guia de frameworks server-side Kotlin.\nQual é o próximo passo depois deste tutorial? Transforme a API de exemplo em um projeto de portfólio: adicione autenticação real, migrations, testes de integração, Docker e um pipeline de CI. O roadmap de backend Kotlin mostra a sequência ideal para sair do tutorial e chegar em projetos que ajudam em entrevistas.\nPara aprofundar seus conhecimentos em Kotlin para backend, confira nosso tutorial sobre Coroutines Avançadas e o guia Kotlin para Backend. Se você trabalha com múltiplas linguagens no backend, compare a abordagem do Ktor com frameworks Go como Gin e Fiber e com FastAPI em Python para APIs modernas.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-ktor-tutorial/","summary":"\u003cp\u003eNeste tutorial, vamos construir uma API REST completa usando o \u003cstrong\u003eKtor\u003c/strong\u003e, o framework web assíncrono e leve criado pela JetBrains especificamente para Kotlin. Você vai aprender desde a configuração inicial do projeto até a integração com banco de dados usando Exposed, passando por routing, serialização JSON, autenticação e testes. Se você quer aprofundar a parte de persistência depois deste guia, veja também o tutorial de \u003ca href=\"/tutoriais/kotlin-postgresql-backend/\"\u003eKotlin com PostgreSQL no backend\u003c/a\u003e. Se você já tem familiaridade com \u003ca href=\"/glossario/fun/\"\u003efunções\u003c/a\u003e e \u003ca href=\"/glossario/coroutine/\"\u003ecoroutines\u003c/a\u003e em Kotlin, está pronto para começar.\u003c/p\u003e","title":"Ktor Framework Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Clean Architecture, proposta por Robert C. Martin, é uma abordagem de organizacao de software que prioriza a separação de responsabilidades é a independencia de frameworks, banco de dados e interfaces externas. Quando aplicada com Kotlin, a Clean Architecture se torna especialmente elegante gracas a recursos como sealed classes, extension functions, data classes e coroutines. Neste guia, vamos implementar Clean Architecture tanto para Android quanto para backend, com exemplos concretos que você pode aplicar diretamente nos seus projetos.\nPrincipios Fundamentais A Clean Architecture se baseia na Regra de Dependencia: as camadas internas não devem conhecer nada sobre as camadas externas. O código-fonte só pode apontar para dentro, nunca para fora. Isso significa que a lógica de negócio não depende de frameworks, banco de dados ou APIs externas.\nAs camadas tipicas são, de dentro para fora: Domain (entidades e use cases), Data (repositórios e fontes de dados) e Presentation (UI e ViewModels). Cada camada comunica-se com a adjacente através de interfaces definidas na camada mais interna.\nEstrutura de Modulos Em projetos maiores, cada camada pode ser um modulo Gradle separado:\n// settings.gradle.kts include(\u0026#34;:app\u0026#34;) // Presentation + DI include(\u0026#34;:domain\u0026#34;) // Entidades + Use Cases + Interfaces include(\u0026#34;:data\u0026#34;) // Implementacoes de Repositórios // domain/build.gradle.kts - Kotlin puro, sem dependências Android plugins { kotlin(\u0026#34;jvm\u0026#34;) } dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3\u0026#34;) } // data/build.gradle.kts dependencies { implementation(project(\u0026#34;:domain\u0026#34;)) implementation(\u0026#34;io.ktor:ktor-client-core:2.3.7\u0026#34;) implementation(\u0026#34;androidx.room:room-ktx:2.6.1\u0026#34;) } // app/build.gradle.kts dependencies { implementation(project(\u0026#34;:domain\u0026#34;)) implementation(project(\u0026#34;:data\u0026#34;)) } Camada Domain A camada Domain e o coracao da aplicação. Ela contém entidades, use cases e interfaces de repositório. Nao possui nenhuma dependência de framework:\n// Entidade de dominio data class Pedido( val id: Long, val clienteId: Long, val itens: List\u0026lt;ItemPedido\u0026gt;, val status: StatusPedido, val criadoEm: LocalDateTime ) { val valorTotal: BigDecimal get() = itens.fold(BigDecimal.ZERO) { acc, item -\u0026gt; acc + (item.precoUnitario * BigDecimal(item.quantidade)) } fun podeSerCancelado(): Boolean { return status == StatusPedido.PENDENTE || status == StatusPedido.CONFIRMADO } } data class ItemPedido( val produtoId: Long, val nomeProduto: String, val quantidade: Int, val precoUnitario: BigDecimal ) enum class StatusPedido { PENDENTE, CONFIRMADO, EM_PREPARO, ENVIADO, ENTREGUE, CANCELADO } Interfaces de Repositorio // Definida no Domain, implementada no Data interface PedidoRepository { suspend fun buscarPorId(id: Long): Pedido? suspend fun buscarPorCliente(clienteId: Long): List\u0026lt;Pedido\u0026gt; suspend fun salvar(pedido: Pedido): Pedido suspend fun atualizar(pedido: Pedido): Pedido fun observarPedidosDoCliente(clienteId: Long): Flow\u0026lt;List\u0026lt;Pedido\u0026gt;\u0026gt; } interface ProdutoRepository { suspend fun buscarPorId(id: Long): Produto? suspend fun verificarEstoque(produtoId: Long): Int } Use Cases Use cases encapsulam regras de negócio específicas. Cada use case tem uma única responsabilidade:\nclass CriarPedidoUseCase( private val pedidoRepository: PedidoRepository, private val produtoRepository: ProdutoRepository ) { suspend operator fun invoke( clienteId: Long, itens: List\u0026lt;ItemPedidoRequest\u0026gt; ): Result\u0026lt;Pedido\u0026gt; { // Validação de negocio if (itens.isEmpty()) { return Result.failure( NegocioException(\u0026#34;Pedido deve ter pelo menos um item\u0026#34;) ) } // Verificar estoque for (item in itens) { val estoque = produtoRepository.verificarEstoque(item.produtoId) if (estoque \u0026lt; item.quantidade) { return Result.failure( NegocioException( \u0026#34;Estoque insuficiente para produto ${item.produtoId}\u0026#34; ) ) } } // Buscar informacoes dos produtos val itensCompletos = itens.map { item -\u0026gt; val produto = produtoRepository.buscarPorId(item.produtoId) ?: return Result.failure( NegocioException(\u0026#34;Produto ${item.produtoId} nao encontrado\u0026#34;) ) ItemPedido( produtoId = produto.id, nomeProduto = produto.nome, quantidade = item.quantidade, precoUnitario = produto.preco ) } val pedido = Pedido( id = 0, clienteId = clienteId, itens = itensCompletos, status = StatusPedido.PENDENTE, criadoEm = LocalDateTime.now() ) val pedidoSalvo = pedidoRepository.salvar(pedido) return Result.success(pedidoSalvo) } } class CancelarPedidoUseCase( private val pedidoRepository: PedidoRepository ) { suspend operator fun invoke(pedidoId: Long): Result\u0026lt;Pedido\u0026gt; { val pedido = pedidoRepository.buscarPorId(pedidoId) ?: return Result.failure( NegocioException(\u0026#34;Pedido $pedidoId nao encontrado\u0026#34;) ) if (!pedido.podeSerCancelado()) { return Result.failure( NegocioException( \u0026#34;Pedido no status ${pedido.status} nao pode ser cancelado\u0026#34; ) ) } val pedidoCancelado = pedido.copy(status = StatusPedido.CANCELADO) val atualizado = pedidoRepository.atualizar(pedidoCancelado) return Result.success(atualizado) } } class ObservarPedidosUseCase( private val pedidoRepository: PedidoRepository ) { operator fun invoke(clienteId: Long): Flow\u0026lt;List\u0026lt;Pedido\u0026gt;\u0026gt; { return pedidoRepository.observarPedidosDoCliente(clienteId) } } O uso de operator fun invoke permite chamar o use case como uma função: criarPedido(clienteId, itens).\nCamada Data A camada Data implementa as interfaces definidas no Domain:\nclass PedidoRepositoryImpl( private val apiService: PedidoApiService, private val pedidoDao: PedidoDao, private val mapper: PedidoMapper ) : PedidoRepository { override suspend fun buscarPorId(id: Long): Pedido? { // Tenta cache local primeiro val local = pedidoDao.buscarPorId(id) if (local != null) { return mapper.entityToDomain(local) } // Busca na API return try { val remoto = apiService.buscarPedido(id) pedidoDao.inserir(mapper.dtoToEntity(remoto)) mapper.dtoToDomain(remoto) } catch (e: Exception) { null } } override suspend fun buscarPorCliente(clienteId: Long): List\u0026lt;Pedido\u0026gt; { return try { val remotos = apiService.buscarPedidosCliente(clienteId) val entidades = remotos.map { mapper.dtoToEntity(it) } pedidoDao.inserirTodos(entidades) remotos.map { mapper.dtoToDomain(it) } } catch (e: Exception) { // Fallback para cache local pedidoDao.buscarPorCliente(clienteId) .map { mapper.entityToDomain(it) } } } override suspend fun salvar(pedido: Pedido): Pedido { val dto = mapper.domainToDto(pedido) val resposta = apiService.criarPedido(dto) pedidoDao.inserir(mapper.dtoToEntity(resposta)) return mapper.dtoToDomain(resposta) } override suspend fun atualizar(pedido: Pedido): Pedido { val dto = mapper.domainToDto(pedido) val resposta = apiService.atualizarPedido(pedido.id, dto) pedidoDao.atualizar(mapper.dtoToEntity(resposta)) return mapper.dtoToDomain(resposta) } override fun observarPedidosDoCliente(clienteId: Long): Flow\u0026lt;List\u0026lt;Pedido\u0026gt;\u0026gt; { return pedidoDao.observarPorCliente(clienteId) .map { entidades -\u0026gt; entidades.map { mapper.entityToDomain(it) } } } } Camada Presentation A camada Presentation contém ViewModels que utilizam os use cases:\nclass PedidoViewModel( private val criarPedido: CriarPedidoUseCase, private val cancelarPedido: CancelarPedidoUseCase, private val observarPedidos: ObservarPedidosUseCase ) : ViewModel() { private val _uiState = MutableStateFlow\u0026lt;PedidoUiState\u0026gt;(PedidoUiState.Loading) val uiState: StateFlow\u0026lt;PedidoUiState\u0026gt; = _uiState.asStateFlow() fun carregarPedidos(clienteId: Long) { viewModelScope.launch { observarPedidos(clienteId).collect { pedidos -\u0026gt; _uiState.value = PedidoUiState.Success(pedidos) } } } fun realizarPedido(clienteId: Long, itens: List\u0026lt;ItemPedidoRequest\u0026gt;) { viewModelScope.launch { _uiState.value = PedidoUiState.Loading criarPedido(clienteId, itens) .onSuccess { _uiState.value = PedidoUiState.PedidoCriado(it) } .onFailure { _uiState.value = PedidoUiState.Error(it.message ?: \u0026#34;Erro\u0026#34;) } } } fun cancelar(pedidoId: Long) { viewModelScope.launch { cancelarPedido(pedidoId) .onFailure { _uiState.value = PedidoUiState.Error(it.message ?: \u0026#34;Erro\u0026#34;) } } } } sealed class PedidoUiState { object Loading : PedidoUiState() data class Success(val pedidos: List\u0026lt;Pedido\u0026gt;) : PedidoUiState() data class PedidoCriado(val pedido: Pedido) : PedidoUiState() data class Error(val mensagem: String) : PedidoUiState() } Boas Práticas para Clean Architecture com Kotlin Mantenha o Domain puro: sem dependências de framework, banco de dados ou bibliotecas de terceiros. Apenas Kotlin puro e coroutines. Use interfaces para inversao de dependência: o Domain define contratos; o Data implementa. Um use case por acao: cada use case deve resolver exatamente um problema de negócio. Use Result ou sealed classes para retornos: evite lancaar exceções para fluxos de negócio previstos. Mapeie entre camadas: cada camada deve ter seus próprios modelos de dados. Nao passe entidades do Room para a UI. Injete dependências: use Koin ou Hilt para conectar as camadas sem acoplamento direto. Teste o Domain independentemente: use cases devem ser testados sem emulador, banco de dados ou rede. Erros Comuns e Armadilhas Anemic use cases: use cases que apenas delegam para o repositório sem adicionar lógica são sinais de que a arquitetura esta sendo aplicada mecanicamente. Simplifique quando não há regra de negócio real. Domain conhecendo o framework: se o Domain importa classes do Android, Room ou Retrofit, a separação esta quebrada. Mapeamento excessivo: para projetos pequenos, tres modelos para a mesma entidade (Domain, Entity, DTO) pode ser overkill. Avalie a complexidade do projeto. Ignorar a testabilidade: se você não esta testando os use cases isoladamente, perde o principal beneficio da Clean Architecture. Camadas desnecessarias: nem todo projeto precisa de Clean Architecture completa. Para projetos simples, MVVM pode ser suficiente. A arquitetura deve servir ao projeto, não o contrario. Conclusão e Próximos Passos Clean Architecture com Kotlin proporciona uma base solida para projetos que precisam escalar e evoluir ao longo do tempo. A separação em camadas facilita testes, manutenção e trabalho em equipe. No entanto, aplique-a com pragmatismo: projetos menores podem se beneficiar de abordagens mais simples. Para aprofundar, explore injeção de dependência com Koin e Hilt, padrões de design complementares e consulte nossos guias sobre testes e MVVM para uma visao completa da arquitetura de aplicações Kotlin. Princípios de Clean Architecture se aplicam em qualquer linguagem — veja como Go estrutura projetos com arquitetura hexagonal e como Rust organiza código com módulos e traits.\n","permalink":"https://kotlin.dev.br/guias/guia-clean-architecture-kotlin/","summary":"\u003cp\u003eClean Architecture, proposta por Robert C. Martin, é uma abordagem de organizacao de software que prioriza a separação de responsabilidades é a independencia de frameworks, banco de dados e interfaces externas. Quando aplicada com Kotlin, a Clean Architecture se torna especialmente elegante gracas a recursos como sealed classes, extension functions, data classes e coroutines. Neste guia, vamos implementar Clean Architecture tanto para Android quanto para backend, com exemplos concretos que você pode aplicar diretamente nos seus projetos.\u003c/p\u003e","title":"Clean Architecture com Kotlin: Guia Completo em Português | Kotlin Brasil"},{"content":"WebAssembly (WASM) é uma das tecnologias mais empolgantes da web moderna, e Kotlin esta na vanguarda dessa revolucao. Com Kotlin/WASM, você pode rodar código Kotlin diretamente no navegador com performance proxima ao código nativo. Vamos explorar o que é Kotlin/WASM, como funciona é o que muda para desenvolvedores.\nO Que e WebAssembly WebAssembly é um formato binario de instrucoes projetado para ser executado em navegadores web (e outros ambientes) com performance quase nativa. Diferente do JavaScript, que e interpretado, WASM e compilado e otimizado, oferecendo velocidade muito superior para tarefas computacionais.\nHistoricamente, WASM era dominio de linguagens como C, C++ e Rust, que é a linguagem mais popular para WASM. Com Kotlin/WASM, a JetBrains trouxe essa capacidade para o ecossistema Kotlin, abrindo novas possibilidades para desenvolvedores.\nKotlin/WASM vs Kotlin/JS E importante distinguir Kotlin/WASM de Kotlin/JS. Kotlin/JS compila Kotlin para JavaScript, que e entao interpretado pelo engine JS do navegador. Kotlin/WASM compila para bytecode WebAssembly, que e executado diretamente pelo runtime WASM do navegador.\nNa prática, isso significa:\nKotlin/JS: Bom para integração com ecossistema JavaScript, performance similar ao JS Kotlin/WASM: Performance muito superior, ideal para computacao intensiva, tamanho de bundle menor Compose for Web com Kotlin/WASM A combinacao mais poderosa e usar Compose Multiplatform com Kotlin/WASM para criar aplicações web:\n// Aplicação web com Compose e Kotlin/WASM @OptIn(ExperimentalComposeUiApi::class) fun main() { CanvasBasedWindow(title = \u0026#34;Minha App Web\u0026#34;) { App() } } @Composable fun App() { MaterialTheme { var selectedTab by remember { mutableStateOf(0) } Scaffold( topBar = { TabRow(selectedTabIndex = selectedTab) { Tab( selected = selectedTab == 0, onClick = { selectedTab = 0 }, text = { Text(\u0026#34;Dashboard\u0026#34;) } ) Tab( selected = selectedTab == 1, onClick = { selectedTab = 1 }, text = { Text(\u0026#34;Relatorios\u0026#34;) } ) } } ) { padding -\u0026gt; when (selectedTab) { 0 -\u0026gt; DashboardScreen(Modifier.padding(padding)) 1 -\u0026gt; RelatoriosScreen(Modifier.padding(padding)) } } } } Isso significa que você pode ter a mesma UI rodando em Android, iOS, desktop e web, tudo escrito em Kotlin com Compose.\nPerformance do Kotlin/WASM Os benchmarks de Kotlin/WASM são impressionantes. Para operações computacionais, a performance e significativamente melhor que Kotlin/JS:\n// Exemplo: processamento de dados no navegador class DataProcessor { fun processarGrandeVolume(dados: List\u0026lt;DataPoint\u0026gt;): ProcessingResult { val agrupados = dados.groupBy { it.categoria } val estatisticas = agrupados.map { (categoria, pontos) -\u0026gt; CategoriaStats( nome = categoria, total = pontos.size, media = pontos.map { it.valor }.average(), mediana = calcularMediana(pontos.map { it.valor }), desvioPadrao = calcularDesvioPadrao(pontos.map { it.valor }), tendencia = calcularTendencia(pontos) ) } return ProcessingResult( totalRegistros = dados.size, categorias = estatisticas, processadoEm = Clock.System.now() ) } private fun calcularMediana(valores: List\u0026lt;Double\u0026gt;): Double { val sorted = valores.sorted() val meio = sorted.size / 2 return if (sorted.size % 2 == 0) { (sorted[meio - 1] + sorted[meio]) / 2.0 } else { sorted[meio] } } private fun calcularDesvioPadrao(valores: List\u0026lt;Double\u0026gt;): Double { val media = valores.average() val variancia = valores.map { (it - media) * (it - media) }.average() return kotlin.math.sqrt(variancia) } } Em Kotlin/WASM, esse tipo de processamento pesado roda muito mais rápido que em JavaScript puro ou Kotlin/JS, tornando viável fazer computacao intensiva diretamente no navegador.\nInteroperabilidade com JavaScript Kotlin/WASM pode interagir com APIs JavaScript quando necessário:\n// Interop com APIs do navegador external interface Document { fun getElementById(id: String): Element? fun createElement(tagName: String): Element } external interface Element { var textContent: String var innerHTML: String fun addEventListener(type: String, listener: (Event) -\u0026gt; Unit) } // Uso de APIs Web fun acessarLocalStorage(chave: String): String? { return js(\u0026#34;window.localStorage.getItem(chave)\u0026#34;) } fun salvarLocalStorage(chave: String, valor: String) { js(\u0026#34;window.localStorage.setItem(chave, valor)\u0026#34;) } A interoperabilidade permite que você use bibliotecas JavaScript existentes quando não há equivalente Kotlin disponivel, mantendo a flexibilidade do ecossistema web.\nConfigurando um Projeto Kotlin/WASM Para começar um projeto Kotlin/WASM, você precisa configurar o Gradle:\n// build.gradle.kts plugins { kotlin(\u0026#34;multiplatform\u0026#34;) version \u0026#34;2.1.0\u0026#34; id(\u0026#34;org.jetbrains.compose\u0026#34;) version \u0026#34;1.7.0\u0026#34; } kotlin { wasmJs { browser { commonWebpackConfig { outputFileName = \u0026#34;app.js\u0026#34; } } binaries.executable() } sourceSets { wasmJsMain.dependencies { implementation(compose.runtime) implementation(compose.ui) implementation(compose.material3) implementation(compose.foundation) } } } Apos a configuração, você pode rodar o projeto com ./gradlew wasmJsBrowserDevelopmentRun e ver sua aplicação Kotlin rodando no navegador.\nCasos de Uso Ideais Aplicações de Visualização de Dados Kotlin/WASM e perfeito para dashboards e ferramentas de visualização que processam grandes volumes de dados:\n@Composable fun GraficoVendas(vendas: List\u0026lt;Venda\u0026gt;) { Canvas(modifier = Modifier.fillMaxWidth().height(300.dp)) { val maxValor = vendas.maxOf { it.valor } val larguraBarra = size.width / vendas.size vendas.forEachIndexed { index, venda -\u0026gt; val altura = (venda.valor / maxValor) * size.height drawRect( color = Color(0xFF6200EE), topLeft = Offset( x = index * larguraBarra + 2, y = size.height - altura.toFloat() ), size = Size( width = larguraBarra - 4, height = altura.toFloat() ) ) } } } Ferramentas de Produtividade Editores de texto, planilhas e ferramentas de design que rodam inteiramente no navegador se beneficiam enormemente da performance do WASM.\nJogos e Simulacoes A performance do WASM torna viável criar jogos 2D e simulacoes interativas diretamente no navegador usando Kotlin.\nLimitações Atuais Kotlin/WASM ainda esta em evolução e tem algumas limitações:\nTamanho do bundle: O runtime Kotlin adiciona peso ao bundle final, embora otimizações estejam reduzindo isso Ecossistema de bibliotecas: Nem todas as bibliotecas Kotlin suportam WASM ainda Debugging: Ferramentas de debug ainda estao amadurecendo Suporte de navegadores: Requer navegadores modernos com suporte completo a WASM GC A JetBrains esta trabalhando ativamente em todas essas areas, e melhorias significativas chegam a cada release.\nO Futuro do Kotlin/WASM O roadmap inclui:\nComponent Model: Integração com o WASM Component Model para melhor interop Otimização de tamanho: Reducao significativa do bundle final WASI: Suporte a WebAssembly System Interface para rodar fora do navegador Compilação incremental: Builds mais rápidos durante desenvolvimento A visao de longo prazo e que Kotlin/WASM permita criar aplicações web com a mesma qualidade e performance de aplicações nativas, usando o mesmo código e ferramentas que você já usa para Android, iOS e desktop.\nConclusão Kotlin/WASM representa uma nova fronteira para desenvolvedores Kotlin. A possibilidade de rodar código Kotlin no navegador com performance nativa abre portas para tipos de aplicação que antes eram impraticaveis na web.\nEmbora ainda em fase de amadurecimento, a tecnologia já e funcional e impressionante. Para desenvolvedores que querem estar na vanguarda, experimentar Kotlin/WASM agora e uma excelente forma de se preparar para o futuro do desenvolvimento web. Se WASM é seu foco principal, vale também explorar Rust, que possui o ecossistema WASM mais maduro com frameworks como Yew e Leptos. Combinado com Compose Multiplatform, Kotlin se posiciona como uma das linguagens mais versáteis para entregar aplicações de alta qualidade em todas as plataformas modernas.\n","permalink":"https://kotlin.dev.br/blog/kotlin-wasm-novidades/","summary":"\u003cp\u003eWebAssembly (WASM) é uma das tecnologias mais empolgantes da web moderna, e Kotlin esta na vanguarda dessa revolucao. Com Kotlin/WASM, você pode rodar código Kotlin diretamente no navegador com performance proxima ao código nativo. Vamos explorar o que é Kotlin/WASM, como funciona é o que muda para desenvolvedores.\u003c/p\u003e\n\u003ch2 id=\"o-que-e-webassembly\"\u003eO Que e WebAssembly\u003c/h2\u003e\n\u003cp\u003eWebAssembly é um formato binario de instrucoes projetado para ser executado em navegadores web (e outros ambientes) com performance quase nativa. Diferente do JavaScript, que e interpretado, WASM e compilado e otimizado, oferecendo velocidade muito superior para tarefas computacionais.\u003c/p\u003e","title":"Kotlin WASM: Novidades e Como Usar WebAssembly com Kotlin | Kotlin Brasil"},{"content":"Neste tutorial completo, você vai aprender a criar uma aplicação Spring Boot com Kotlin do zero. Vamos cobrir a configuração do projeto, REST controllers, services, repositórios com Spring Data JPA, funcionalidades específicas do Kotlin no Spring, integração com Coroutines e configuração avançada. Kotlin é uma linguagem oficialmente suportada pelo Spring e oferece uma experiência de desenvolvimento mais concisa e segura que o Java.\nPor que usar Kotlin com Spring Boot? O Spring Framework oferece suporte oficial ao Kotlin desde a versão 5.0, é o Spring Boot desde a versão 2.0. As vantagens incluem:\nNull safety: o sistema de tipos do Kotlin com nullable elimina NullPointerExceptions em tempo de compilação Data classes: perfeitas para DTOs e entidades, eliminando getters, setters, equals, hashCode e toString Extension functions: permitem estender classes do Spring de forma elegante Coroutines: suporte nativo para programação assíncrona não-bloqueante Código conciso: menos boilerplate que Java, mantendo a mesma funcionalidade Passo 1: Criando o Projeto A maneira mais fácil de criar um projeto Spring Boot com Kotlin é usando o Spring Initializr. Selecione:\nLanguage: Kotlin Build: Gradle - Kotlin Dependencies: Spring Web, Spring Data JPA, H2 Database (ou PostgreSQL), Spring Validation O build.gradle.kts deve incluir os plugins e dependências essenciais:\nimport org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id(\u0026#34;org.springframework.boot\u0026#34;) version \u0026#34;3.2.3\u0026#34; id(\u0026#34;io.spring.dependency-management\u0026#34;) version \u0026#34;1.1.4\u0026#34; kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;1.9.22\u0026#34; kotlin(\u0026#34;plugin.spring\u0026#34;) version \u0026#34;1.9.22\u0026#34; // abre classes para proxying kotlin(\u0026#34;plugin.jpa\u0026#34;) version \u0026#34;1.9.22\u0026#34; // gera construtor sem args para JPA } dependencies { implementation(\u0026#34;org.springframework.boot:spring-boot-starter-web\u0026#34;) implementation(\u0026#34;org.springframework.boot:spring-boot-starter-data-jpa\u0026#34;) implementation(\u0026#34;org.springframework.boot:spring-boot-starter-validation\u0026#34;) implementation(\u0026#34;com.fasterxml.jackson.module:jackson-module-kotlin\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlin:kotlin-reflect\u0026#34;) // Coroutines (opcional) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-reactor\u0026#34;) runtimeOnly(\u0026#34;com.h2database:h2\u0026#34;) // banco em memoria para desenvolvimento // runtimeOnly(\u0026#34;org.postgresql:postgresql\u0026#34;) // para produção testImplementation(\u0026#34;org.springframework.boot:spring-boot-starter-test\u0026#34;) } tasks.withType\u0026lt;KotlinCompile\u0026gt; { kotlinOptions { freeCompilerArgs += \u0026#34;-Xjsr305=strict\u0026#34; // null safety para anotações Java jvmTarget = \u0026#34;17\u0026#34; } } Os plugins plugin.spring e plugin.jpa são essenciais: o primeiro adiciona o modificador open automaticamente às classes com anotações Spring (já que o Kotlin cria classes final por padrão), e o segundo gera construtores sem argumentos necessários pelo JPA.\nPasso 2: Configurando a Aplicação O ponto de entrada da aplicação:\nimport org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication @SpringBootApplication class Application fun main(args: Array\u0026lt;String\u0026gt;) { runApplication\u0026lt;Application\u0026gt;(*args) } Note que usamos runApplication — uma extension function do Spring para Kotlin que simplifica a inicialização. O application.yml (ou application.properties) configura o ambiente:\n// application.yml // spring: // datasource: // url: jdbc:h2:mem:testdb // driver-class-name: org.h2.Driver // jpa: // hibernate: // ddl-auto: update // show-sql: true // h2: // console: // enabled: true // server: // port: 8080 Passo 3: Criando a Entity com JPA Com Kotlin, usamos data classes para entidades, mas com algumas considerações especiais para o JPA:\nimport jakarta.persistence.* import java.time.LocalDateTime @Entity @Table(name = \u0026#34;produtos\u0026#34;) data class Produto( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0, @Column(nullable = false, length = 100) val nome: String, @Column(length = 500) val descricao: String = \u0026#34;\u0026#34;, @Column(nullable = false) val preco: Double, @Column(name = \u0026#34;em_estoque\u0026#34;) val emEstoque: Boolean = true, @Column(name = \u0026#34;criado_em\u0026#34;) val criadoEm: LocalDateTime = LocalDateTime.now() ) O plugin kotlin-jpa gera o construtor sem argumentos que o Hibernate precisa. Os valores padrão nos parâmetros permitem criar instâncias parciais sem precisar de builders.\nPara DTOs de entrada e saída, usamos data classes simples com válidação:\nimport jakarta.validation.constraints.NotBlank import jakarta.validation.constraints.Positive import jakarta.validation.constraints.Size data class ProdutoRequest( @field:NotBlank(message = \u0026#34;Nome e obrigatorio\u0026#34;) @field:Size(min = 2, max = 100, message = \u0026#34;Nome deve ter entre 2 e 100 caracteres\u0026#34;) val nome: String, val descricao: String = \u0026#34;\u0026#34;, @field:Positive(message = \u0026#34;Preço deve ser positivo\u0026#34;) val preco: Double ) data class ProdutoResponse( val id: Long, val nome: String, val descricao: String, val preco: Double, val emEstoque: Boolean, val criadoEm: LocalDateTime ) { companion object { fun fromEntity(produto: Produto) = ProdutoResponse( id = produto.id, nome = produto.nome, descricao = produto.descricao, preco = produto.preco, emEstoque = produto.emEstoque, criadoEm = produto.criadoEm ) } } Note o uso de @field: antes das anotações de válidação — isso é necessário em Kotlin para que as anotações sejam aplicadas ao campo Java subjacente e não ao parâmetro do construtor.\nPasso 4: Criando o Repository com Spring Data JPA O Spring Data JPA gera a implementação do repositório automaticamente a partir da interface:\nimport org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query import org.springframework.stereotype.Repository @Repository interface ProdutoRepository : JpaRepository\u0026lt;Produto, Long\u0026gt; { // Query derivada do nome do metodo fun findByNomeContainingIgnoreCase(nome: String): List\u0026lt;Produto\u0026gt; fun findByEmEstoque(emEstoque: Boolean): List\u0026lt;Produto\u0026gt; fun findByPrecoLessThanEqual(precoMaximo: Double): List\u0026lt;Produto\u0026gt; // Query JPQL personalizada @Query(\u0026#34;SELECT p FROM Produto p WHERE p.preco BETWEEN :min AND :max ORDER BY p.preco\u0026#34;) fun findByFaixaDePreco(min: Double, max: Double): List\u0026lt;Produto\u0026gt; // Query nativa @Query( value = \u0026#34;SELECT * FROM produtos WHERE em_estoque = true ORDER BY criado_em DESC LIMIT :limite\u0026#34;, nativeQuery = true ) fun findRecentes(limite: Int): List\u0026lt;Produto\u0026gt; fun countByEmEstoque(emEstoque: Boolean): Long } O Spring Data interpreta o nome do método e gera a query SQL automaticamente. Para consultas mais complexas, use @Query com JPQL ou SQL nativo.\nPasso 5: Criando o Service A camada de serviço contém a lógica de negócios:\nimport org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @Service class ProdutoService( private val repository: ProdutoRepository ) { fun listarTodos(): List\u0026lt;ProdutoResponse\u0026gt; { return repository.findAll().map { ProdutoResponse.fromEntity(it) } } fun buscarPorId(id: Long): ProdutoResponse { val produto = repository.findById(id) .orElseThrow { ProdutoNaoEncontradoException(id) } return ProdutoResponse.fromEntity(produto) } fun buscarPorNome(nome: String): List\u0026lt;ProdutoResponse\u0026gt; { return repository.findByNomeContainingIgnoreCase(nome) .map { ProdutoResponse.fromEntity(it) } } @Transactional fun criar(request: ProdutoRequest): ProdutoResponse { val produto = Produto( nome = request.nome, descricao = request.descricao, preco = request.preco ) val salvo = repository.save(produto) return ProdutoResponse.fromEntity(salvo) } @Transactional fun atualizar(id: Long, request: ProdutoRequest): ProdutoResponse { val existente = repository.findById(id) .orElseThrow { ProdutoNaoEncontradoException(id) } val atualizado = existente.copy( nome = request.nome, descricao = request.descricao, preco = request.preco ) val salvo = repository.save(atualizado) return ProdutoResponse.fromEntity(salvo) } @Transactional fun deletar(id: Long) { if (!repository.existsById(id)) { throw ProdutoNaoEncontradoException(id) } repository.deleteById(id) } } class ProdutoNaoEncontradoException(id: Long) : RuntimeException(\u0026#34;Produto com ID $id nao encontrado\u0026#34;) Note como o Kotlin torna o código mais limpo: injeção de dependência pelo construtor, copy() para atualização parcial, e string templates para mensagens de erro.\nPasso 6: Criando o REST Controller O controller expõe os endpoints da API:\nimport jakarta.validation.Valid import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* @RestController @RequestMapping(\u0026#34;/api/produtos\u0026#34;) class ProdutoController( private val service: ProdutoService ) { @GetMapping fun listarTodos(): ResponseEntity\u0026lt;List\u0026lt;ProdutoResponse\u0026gt;\u0026gt; { return ResponseEntity.ok(service.listarTodos()) } @GetMapping(\u0026#34;/{id}\u0026#34;) fun buscarPorId(@PathVariable id: Long): ResponseEntity\u0026lt;ProdutoResponse\u0026gt; { return ResponseEntity.ok(service.buscarPorId(id)) } @GetMapping(\u0026#34;/buscar\u0026#34;) fun buscarPorNome(@RequestParam nome: String): ResponseEntity\u0026lt;List\u0026lt;ProdutoResponse\u0026gt;\u0026gt; { return ResponseEntity.ok(service.buscarPorNome(nome)) } @PostMapping fun criar(@Valid @RequestBody request: ProdutoRequest): ResponseEntity\u0026lt;ProdutoResponse\u0026gt; { val produto = service.criar(request) return ResponseEntity.status(HttpStatus.CREATED).body(produto) } @PutMapping(\u0026#34;/{id}\u0026#34;) fun atualizar( @PathVariable id: Long, @Valid @RequestBody request: ProdutoRequest ): ResponseEntity\u0026lt;ProdutoResponse\u0026gt; { return ResponseEntity.ok(service.atualizar(id, request)) } @DeleteMapping(\u0026#34;/{id}\u0026#34;) fun deletar(@PathVariable id: Long): ResponseEntity\u0026lt;Unit\u0026gt; { service.deletar(id) return ResponseEntity.noContent().build() } } Passo 7: Tratamento Global de Erros Use @ControllerAdvice para tratar exceções de forma centralizada:\nimport org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.MethodArgumentNotValidException import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler data class ErroResponse( val status: Int, val mensagem: String, val erros: List\u0026lt;String\u0026gt; = emptyList() ) @ControllerAdvice class GlobalExceptionHandler { @ExceptionHandler(ProdutoNaoEncontradoException::class) fun handleNaoEncontrado(ex: ProdutoNaoEncontradoException): ResponseEntity\u0026lt;ErroResponse\u0026gt; { val erro = ErroResponse( status = HttpStatus.NOT_FOUND.value(), mensagem = ex.message ?: \u0026#34;Recurso nao encontrado\u0026#34; ) return ResponseEntity.status(HttpStatus.NOT_FOUND).body(erro) } @ExceptionHandler(MethodArgumentNotValidException::class) fun handleValidacao(ex: MethodArgumentNotValidException): ResponseEntity\u0026lt;ErroResponse\u0026gt; { val erros = ex.bindingResult.fieldErrors.map { \u0026#34;${it.field}: ${it.defaultMessage}\u0026#34; } val erro = ErroResponse( status = HttpStatus.BAD_REQUEST.value(), mensagem = \u0026#34;Erro de validação\u0026#34;, erros = erros ) return ResponseEntity.badRequest().body(erro) } @ExceptionHandler(Exception::class) fun handleGenerico(ex: Exception): ResponseEntity\u0026lt;ErroResponse\u0026gt; { val erro = ErroResponse( status = HttpStatus.INTERNAL_SERVER_ERROR.value(), mensagem = \u0026#34;Erro interno do servidor\u0026#34; ) return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(erro) } } Passo 8: Coroutines no Spring O Spring Boot suporta Coroutines nativamente com o módulo WebFlux. Você pode usar funções suspend e Flow diretamente nos controllers:\nimport kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import org.springframework.web.bind.annotation.* @RestController @RequestMapping(\u0026#34;/api/async\u0026#34;) class AsyncController( private val service: AsyncService ) { // Endpoint com suspend function @GetMapping(\u0026#34;/produto/{id}\u0026#34;) suspend fun buscarProduto(@PathVariable id: Long): ProdutoResponse { return service.buscarProdutoAsync(id) } // Endpoint que retorna Flow (streaming) @GetMapping(\u0026#34;/stream\u0026#34;) fun streamProdutos(): Flow\u0026lt;ProdutoResponse\u0026gt; = flow { val produtos = service.listarTodosAsync() produtos.forEach { produto -\u0026gt; delay(100) // simula processamento emit(produto) } } } @Service class AsyncService( private val repository: ProdutoRepository ) { suspend fun buscarProdutoAsync(id: Long): ProdutoResponse { // Em aplicacoes reais, use R2DBC para acesso nao-bloqueante ao banco val produto = repository.findById(id) .orElseThrow { ProdutoNaoEncontradoException(id) } return ProdutoResponse.fromEntity(produto) } suspend fun listarTodosAsync(): List\u0026lt;ProdutoResponse\u0026gt; { return repository.findAll().map { ProdutoResponse.fromEntity(it) } } } Para aproveitar ao máximo as coroutines no Spring, considere usar Spring WebFlux com R2DBC em vez do Spring MVC com JPA, pois o JPA tradicional é bloqueante por natureza.\nPasso 9: Funcionalidades Kotlin-Specific no Spring O Spring oferece várias extensões para Kotlin que tornam o código mais idiomático:\nimport org.springframework.beans.factory.getBean import org.springframework.context.support.beans // Bean definition DSL — alternativa a @Configuration val beans = beans { bean\u0026lt;ProdutoService\u0026gt;() bean { ProdutoController(ref()) } } // Router DSL — alternativa funcional aos controllers import org.springframework.web.servlet.function.router fun produtoRoutes(service: ProdutoService) = router { \u0026#34;/api/produtos\u0026#34;.nest { GET(\u0026#34;\u0026#34;) { _ -\u0026gt; ok().body(service.listarTodos()) } GET(\u0026#34;/{id}\u0026#34;) { request -\u0026gt; val id = request.pathVariable(\u0026#34;id\u0026#34;).toLong() ok().body(service.buscarPorId(id)) } POST(\u0026#34;\u0026#34;) { request -\u0026gt; val body = request.body(ProdutoRequest::class.java) status(HttpStatus.CREATED).body(service.criar(body)) } } } Essas DSLs são opcionais e oferecem uma abordagem funcional como alternativa às anotações tradicionais.\nErros Comuns Esquecer o plugin kotlin-spring: Sem esse plugin, as classes Kotlin são final por padrão, e o Spring não consegue criar proxies para injeção de dependência e transações. O plugin adiciona open automaticamente.\nNão usar @field: nas anotações de válidação: Em Kotlin, anotações em propriedades do construtor primário precisam do target @field: para que as válidações do Bean Validation funcionem corretamente.\nUsar var nas Entities sem necessidade: Prefira val e use copy() para criar versões modificadas. Entidades mutáveis são fonte de bugs difíceis de rastrear.\nIgnorar o -Xjsr305=strict: Essa flag do compilador faz com que as anotações de nulidade do Java (como @Nullable e @NonNull do Spring) sejam respeitadas pelo tipo do Kotlin, melhorando a segurança de tipos.\nMisturar JPA bloqueante com coroutines sem cuidado: Usar suspend no controller com JPA tradicional não torna o acesso ao banco não-bloqueante. Para I/O verdadeiramente assíncrono, use R2DBC.\nConclusão e Próximos Passos Neste tutorial, você aprendeu a criar uma aplicação Spring Boot completa com Kotlin: configuração do projeto com plugins essenciais, entidades JPA com data classes, repositórios com Spring Data JPA, services com lógica de negócios, REST controllers com válidação, tratamento global de erros, coroutines no Spring, e funcionalidades específicas do Kotlin como Router DSL e Bean DSL.\nComo próximos passos, recomendamos:\nExplorar Spring Security com Kotlin para autenticação e autorização Estudar R2DBC para acesso não-bloqueante ao banco de dados com coroutines Aprender sobre testes com MockK (alternativa Kotlin-friendly ao Mockito) Implementar documentação da API com SpringDoc/Swagger Consultar o glossário de extension function e interface para reforçar conceitos Explorar o Kotlin Flow para streaming de dados no backend Spring Boot com Kotlin é uma combinação poderosa para desenvolvimento backend, oferecendo produtividade, segurança de tipos e todo o ecossistema maduro do Spring Framework.\nSe você quer comparar frameworks backend em outras linguagens, Go com Gin e Echo oferece APIs leves e performáticas, enquanto Python com Django e FastAPI domina em prototipagem rápida.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-spring-boot-tutorial/","summary":"\u003cp\u003eNeste tutorial completo, você vai aprender a criar uma aplicação \u003cstrong\u003eSpring Boot com Kotlin\u003c/strong\u003e do zero. Vamos cobrir a configuração do projeto, REST controllers, services, repositórios com Spring Data JPA, funcionalidades específicas do Kotlin no Spring, integração com \u003ca href=\"/glossario/coroutine/\"\u003eCoroutines\u003c/a\u003e e configuração avançada. Kotlin é uma linguagem oficialmente suportada pelo Spring e oferece uma experiência de desenvolvimento mais concisa e segura que o Java.\u003c/p\u003e\n\u003ch2 id=\"por-que-usar-kotlin-com-spring-boot\"\u003ePor que usar Kotlin com Spring Boot?\u003c/h2\u003e\n\u003cp\u003eO Spring Framework oferece suporte oficial ao Kotlin desde a versão 5.0, é o Spring Boot desde a versão 2.0. As vantagens incluem:\u003c/p\u003e","title":"Spring Boot com Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Testes em Kotlin não são apenas uma etapa burocrática antes do deploy. Eles são a forma mais barata de descobrir se uma regra de negócio continua correta depois de uma refatoração, se uma coroutine respeita cancelamento, se um Flow emite os estados esperados, se um endpoint Ktor ou Spring Boot conversa com o banco de verdade e se uma tela Android continua funcionando depois de trocar XML por Jetpack Compose.\nEste guia organiza uma estratégia prática para projetos Kotlin em 2026: JUnit 5 para execução, MockK para mocks idiomáticos, Kotest quando o time quer uma DSL mais expressiva, kotlinx-coroutines-test para código assíncrono, Turbine para Flow, Testcontainers para integração realista e testes Android quando a UI ou o framework precisam entrar na conta.\nSe você está começando, não tente automatizar tudo de uma vez. Monte uma pirâmide simples: muitos testes unitários rápidos, alguns testes de integração cobrindo banco/API e poucos testes de ponta a ponta para fluxos críticos. Depois conecte essa suíte ao seu pipeline de CI/CD em Kotlin e complemente com detekt e ktlint para manter qualidade de código e comportamento sob controle.\nO que testar em um projeto Kotlin? Antes das ferramentas, defina o alvo. Um projeto saudável costuma separar os testes assim:\nTestes unitários: validam funções, serviços, use cases, validators, mappers e regras de domínio sem I/O real. Testes de coroutines e Flow: validam concorrência, tempo virtual, cancelamento, retries e sequências de estado. Testes de integração: sobem banco, fila, HTTP client, repository ou endpoint real para pegar erro de configuração. Testes Android locais: rodam na JVM com Robolectric ou com componentes isolados quando o Android framework aparece. Testes instrumentados: rodam em emulador/device e validam Room, Compose, navegação, permissões ou integração com o sistema. Testes end-to-end: cobrem jornadas de produto com ferramentas como Maestro, Espresso, Playwright mobile ou device farms. A armadilha comum é pular direto para testes de UI porque eles parecem mais próximos do usuário. Eles são úteis, mas lentos e mais frágeis. A maior parte do comportamento deve estar em camadas testáveis sem Android framework: ViewModel, use case, repository, parser, policy, regra de preço, regra de sincronização e serialização.\nConfiguração base com Gradle Kotlin DSL Para um projeto Kotlin JVM ou backend, comece com dependências parecidas com estas:\ndependencies { testImplementation(kotlin(\u0026#34;test\u0026#34;)) testImplementation(\u0026#34;org.junit.jupiter:junit-jupiter:5.10.3\u0026#34;) testRuntimeOnly(\u0026#34;org.junit.platform:junit-platform-launcher\u0026#34;) testImplementation(\u0026#34;io.mockk:mockk:1.13.12\u0026#34;) testImplementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1\u0026#34;) testImplementation(\u0026#34;app.cash.turbine:turbine:1.1.0\u0026#34;) testImplementation(\u0026#34;io.kotest:kotest-assertions-core:5.9.1\u0026#34;) testImplementation(\u0026#34;org.testcontainers:junit-jupiter:1.20.1\u0026#34;) testImplementation(\u0026#34;org.testcontainers:postgresql:1.20.1\u0026#34;) } tasks.test { useJUnitPlatform() } Em Android, a ideia é parecida, mas as configurações entram nos blocos testImplementation e androidTestImplementation:\ndependencies { testImplementation(\u0026#34;junit:junit:4.13.2\u0026#34;) testImplementation(\u0026#34;io.mockk:mockk:1.13.12\u0026#34;) testImplementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1\u0026#34;) androidTestImplementation(\u0026#34;androidx.test.ext:junit:1.1.5\u0026#34;) androidTestImplementation(\u0026#34;androidx.test.espresso:espresso-core:3.5.1\u0026#34;) androidTestImplementation(\u0026#34;androidx.compose.ui:ui-test-junit4\u0026#34;) } Use versões compatíveis com o Android Gradle Plugin e com o Kotlin do seu projeto. O objetivo aqui é mostrar o desenho, não congelar números para todos os times.\nTestes unitários com JUnit 5 JUnit 5 continua sendo a opção mais comum para suites Kotlin porque é simples, estável e integra bem com Gradle, IDEs e CI. Kotlin permite nomes de teste com backticks, o que deixa o relatório mais legível:\nclass CalculadoraDeFreteTest { private val calculadora = CalculadoraDeFrete() @Test fun `deve aplicar frete gratis acima do valor minimo`() { val frete = calculadora.calcular( subtotal = 250.0, cep = \u0026#34;01001-000\u0026#34;, ) assertEquals(0.0, frete) } @Test fun `deve rejeitar subtotal negativo`() { assertThrows\u0026lt;IllegalArgumentException\u0026gt; { calculadora.calcular(subtotal = -10.0, cep = \u0026#34;01001-000\u0026#34;) } } } Prefira testar comportamento observável. Se uma refatoração interna quebra muitos testes sem mudar resultado público, talvez os testes estejam presos à implementação. Esse é um sinal para testar pelo contrato da classe, não por detalhes como “chamou método privado X”.\nMockK para dependências externas MockK entende melhor o Kotlin do que mocks genéricos do ecossistema Java: classes finais, funções suspensas, objetos, relaxed mocks e DSL idiomática. Use mocks para isolar I/O, APIs, repositórios externos e relógios, mas evite mockar tudo.\nclass PedidoServiceTest { private val gateway = mockk\u0026lt;PagamentoGateway\u0026gt;() private val repository = mockk\u0026lt;PedidoRepository\u0026gt;() private val service = PedidoService(gateway, repository) @Test fun `deve salvar pedido aprovado`() { every { gateway.autorizar(any()) } returns Autorizacao(aprovada = true) every { repository.salvar(any()) } returns Pedido(id = 42, status = \u0026#34;APROVADO\u0026#34;) val pedido = service.criar(PedidoRequest(valor = 120.0)) assertEquals(\u0026#34;APROVADO\u0026#34;, pedido.status) verify(exactly = 1) { repository.salvar(match { it.valor == 120.0 }) } } } Quando o teste exige cinco ou seis mocks para uma classe pequena, investigue o design. Pode ser que a classe esteja coordenando responsabilidades demais ou que falte uma abstração mais simples.\nCoroutines com runTest Para funções suspensas, use runTest. Ele controla tempo virtual, evita sleeps reais e ajuda a detectar coroutines penduradas:\nclass SincronizadorTest { private val api = mockk\u0026lt;TarefasApi\u0026gt;() private val dao = mockk\u0026lt;TarefaDao\u0026gt;(relaxed = true) private val sincronizador = Sincronizador(api, dao) @Test fun `deve marcar tarefa como sincronizada depois do envio`() = runTest { coEvery { api.enviar(any()) } returns Unit sincronizador.enviar(TarefaPendente(id = 10, titulo = \u0026#34;Revisar PR\u0026#34;)) coVerify { api.enviar(match { it.id == 10L }) } coVerify { dao.marcarComoSincronizada(10L) } } } Evite runBlocking em testes novos. Ele pode mascarar problemas de tempo, deixar a suíte mais lenta e dificultar cenários com delay, timeout e retry.\nTestando Flow com Turbine Flow aparece em Android, backend reativo e pipelines assíncronos. Para validar emissões, Turbine deixa o teste explícito:\n@Test fun `deve emitir loading e sucesso ao carregar perfil`() = runTest { coEvery { api.buscarPerfil() } returns Perfil(nome = \u0026#34;Ana\u0026#34;) viewModel.estado.test { assertEquals(PerfilState.Loading, awaitItem()) viewModel.carregar() assertEquals(PerfilState.Sucesso(\u0026#34;Ana\u0026#34;), awaitItem()) cancelAndIgnoreRemainingEvents() } } Em ViewModels Android, configure o dispatcher principal no teste com uma regra própria ou extensão. O ponto é não depender do Dispatchers.Main real em ambiente JVM.\nIntegração com Testcontainers Mocks são ótimos para regras, mas ruins para provar que SQL, migrations, JSONB, índices e transações funcionam. Para backend Kotlin com Ktor, Spring Boot ou Exposed, Testcontainers costuma pagar o custo rapidamente:\n@Testcontainers class UsuarioRepositoryTest { companion object { @Container val postgres = PostgreSQLContainer(\u0026#34;postgres:16-alpine\u0026#34;) } @Test fun `deve persistir usuario com email unico`() { val dataSource = criarDataSource(postgres.jdbcUrl, postgres.username, postgres.password) val repository = UsuarioRepository(dataSource) val usuario = repository.criar(email = \u0026#34;ana@example.com\u0026#34;) assertNotNull(usuario.id) assertEquals(\u0026#34;ana@example.com\u0026#34;, repository.buscarPorId(usuario.id)?.email) } } Esse tipo de teste é mais lento que um unitário, então rode menos casos e escolha cenários de alto risco: migrations, constraints, queries complexas, paginação, transações e serialização. Para uma API Ktor completa, combine com testes de rota e um banco real. Para Spring Boot, use slices como @DataJpaTest quando fizer sentido.\nTestes Android: local, Compose e instrumentado Em Android, tente empurrar regra de negócio para fora da Activity/Composable. ViewModel com StateFlow, use cases e repositories são fáceis de testar na JVM. Deixe testes instrumentados para o que realmente depende do framework. Para uma trilha dedicada ao ecossistema mobile, veja o guia de testes Android com Kotlin, Compose e Maestro.\nPara Compose, use tags estáveis:\n@Test fun loginValido_deveAbrirHome() { composeRule.setContent { LoginScreen(onLogin = { sucesso = true }) } composeRule.onNodeWithTag(\u0026#34;email_field\u0026#34;).performTextInput(\u0026#34;ana@example.com\u0026#34;) composeRule.onNodeWithTag(\u0026#34;password_field\u0026#34;).performTextInput(\u0026#34;senha-segura\u0026#34;) composeRule.onNodeWithTag(\u0026#34;login_button\u0026#34;).performClick() composeRule.onNodeWithTag(\u0026#34;home_screen\u0026#34;).assertIsDisplayed() } Para jornadas maiores, Maestro pode ser mais simples que manter centenas de interações Espresso. Ainda assim, não transforme toda regra em teste E2E. Um fluxo de login, uma compra, um sync offline-first e um deep link crítico podem bastar.\nOnde encaixar no CI/CD Uma pipeline realista para Kotlin deve separar custo e feedback:\n./gradlew test em todo pull request. ./gradlew ktlintCheck detekt junto com testes unitários. Testes de integração com Testcontainers em PRs que mexem em backend, repository ou banco. Testes instrumentados Android em branch principal, PRs críticos ou matriz reduzida de emuladores. Testes E2E apenas para fluxos de negócio que justificam manutenção. O guia de GitHub Actions para Kotlin mostra a base do workflow. O importante é não esconder falhas com continue-on-error em etapas essenciais. Teste instável deve ser corrigido, isolado ou removido; não deve virar ruído permanente.\nChecklist de uma boa suíte Kotlin Testes unitários rodam em segundos e não dependem de rede, banco ou relógio real. Nomes de teste explicam cenário, ação e expectativa. Coroutines usam runTest, dispatchers controlados e tempo virtual quando necessário. Flow é validado por emissões, não por sleeps. Integração usa banco real quando SQL/migration importa. Android mantém regra fora da UI e testa Compose apenas onde a tela é o contrato. Fixtures e builders reduzem duplicação sem esconder o caso testado. CI bloqueia regressões importantes e mantém logs legíveis. Erros comuns Mockar o domínio inteiro: se tudo é mock, o teste só prova que o mock foi configurado. Testar detalhe interno: refatorações simples quebram a suíte sem mudar comportamento. Usar delay real: deixa testes lentos e instáveis; prefira tempo virtual. Ignorar cenários de erro: timeout, resposta vazia, conflito, permissão negada e dado inválido costumam quebrar produção. Confiar apenas em SQLite em memória: para PostgreSQL, MySQL ou SQL Server, comportamento de tipos e constraints pode mudar. Rodar E2E demais: teste lento demais vira gargalo e incentiva o time a ignorar a suíte. Próximos passos Se seu projeto hoje quase não tem testes, comece por uma regra de domínio que muda com frequência e por um bug recente que não deveria voltar. Depois cubra ViewModels, repositories críticos e um fluxo de integração com banco. Para Android offline-first, complemente este guia com a arquitetura de Room, WorkManager e Flow. Para backend, avance para Ktor, Spring Boot e PostgreSQL com Kotlin.\nUma suíte bem desenhada não garante que o produto esteja certo, mas reduz muito o custo de evoluir com confiança. Em Kotlin, a combinação de linguagem expressiva, coroutines testáveis, DSLs claras e integração forte com Gradle permite chegar nesse ponto sem transformar testes em um projeto paralelo.\nPara comparar estilos em outros ecossistemas, veja como Go testa com o pacote testing integrado e como Python usa pytest para testes expressivos.\n","permalink":"https://kotlin.dev.br/guias/guia-testes-kotlin/","summary":"\u003cp\u003eTestes em Kotlin não são apenas uma etapa burocrática antes do deploy. Eles são a forma mais barata de descobrir se uma regra de negócio continua correta depois de uma refatoração, se uma coroutine respeita cancelamento, se um \u003ccode\u003eFlow\u003c/code\u003e emite os estados esperados, se um endpoint Ktor ou Spring Boot conversa com o banco de verdade e se uma tela Android continua funcionando depois de trocar XML por Jetpack Compose.\u003c/p\u003e","title":"Testes em Kotlin: Guia Completo para JVM, Android e Backend | Kotlin Brasil"},{"content":"O Ktor é o framework web oficial da JetBrains, construido inteiramente em Kotlin e projetado para aproveitar ao maximo os recursos da linguagem, especialmente coroutines. Diferente do Spring Boot, que traz um ecossistema completo e opinado, o Ktor segue uma filosofia minimalista e modular: você instala apenas os plugins que precisa, mantendo a aplicação leve é o startup rápido. Isso o torna ideal para microsserviços, APIs e aplicações que exigem alta performance com baixo consumo de recursos. Neste guia, vamos construir uma API completa com Ktor, cobrindo rotas, serialização, banco de dados, autenticação e deploy.\nConfigurando o Projeto O Ktor Project Generator (start.ktor.io) cria a estrutura inicial. A configuração no build.gradle.kts:\nplugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;1.9.22\u0026#34; id(\u0026#34;io.ktor.plugin\u0026#34;) version \u0026#34;2.3.7\u0026#34; kotlin(\u0026#34;plugin.serialization\u0026#34;) version \u0026#34;1.9.22\u0026#34; } application { mainClass.set(\u0026#34;com.exemplo.ApplicationKt\u0026#34;) } dependencies { // Core implementation(\u0026#34;io.ktor:ktor-server-core-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-netty-jvm\u0026#34;) // Plugins implementation(\u0026#34;io.ktor:ktor-server-content-negotiation-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-serialization-kotlinx-json-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-status-pages-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-auth-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-auth-jwt-jvm\u0026#34;) implementation(\u0026#34;io.ktor:ktor-server-cors-jvm\u0026#34;) // Banco de dados implementation(\u0026#34;org.jetbrains.exposed:exposed-core:0.46.0\u0026#34;) implementation(\u0026#34;org.jetbrains.exposed:exposed-dao:0.46.0\u0026#34;) implementation(\u0026#34;org.jetbrains.exposed:exposed-jdbc:0.46.0\u0026#34;) implementation(\u0026#34;org.jetbrains.exposed:exposed-java-time:0.46.0\u0026#34;) implementation(\u0026#34;org.postgresql:postgresql:42.7.1\u0026#34;) implementation(\u0026#34;com.zaxxer:HikariCP:5.1.0\u0026#34;) // Logging implementation(\u0026#34;ch.qos.logback:logback-classic:1.4.14\u0026#34;) // Testes testImplementation(\u0026#34;io.ktor:ktor-server-tests-jvm\u0026#34;) testImplementation(\u0026#34;org.jetbrains.kotlin:kotlin-test-junit\u0026#34;) } Estrutura da Aplicação O Ktor usa uma função main simples para iniciar o servidor:\nfun main() { embeddedServer(Netty, port = 8080, host = \u0026#34;0.0.0.0\u0026#34;) { configurarPlugins() configurarRoteamento() configurarBancoDeDados() }.start(wait = true) } // Ou usando application.conf (HOCON) fun main(args: Array\u0026lt;String\u0026gt;) { io.ktor.server.netty.EngineMain.main(args) } fun Application.module() { configurarPlugins() configurarRoteamento() configurarBancoDeDados() } Configurando Plugins Os plugins adicionam funcionalidades ao Ktor de forma modular:\nfun Application.configurarPlugins() { install(ContentNegotiation) { json(Json { prettyPrint = true isLenient = true ignoreUnknownKeys = true encodeDefaults = true }) } install(StatusPages) { exception\u0026lt;RecursoNaoEncontradoException\u0026gt; { call, causa -\u0026gt; call.respond( HttpStatusCode.NotFound, ErroResponse(404, causa.message ?: \u0026#34;Nao encontrado\u0026#34;) ) } exception\u0026lt;ValidacaoException\u0026gt; { call, causa -\u0026gt; call.respond( HttpStatusCode.BadRequest, ErroResponse(400, causa.message ?: \u0026#34;Dados invalidos\u0026#34;) ) } exception\u0026lt;Throwable\u0026gt; { call, causa -\u0026gt; call.application.environment.log.error(\u0026#34;Erro interno\u0026#34;, causa) call.respond( HttpStatusCode.InternalServerError, ErroResponse(500, \u0026#34;Erro interno do servidor\u0026#34;) ) } } install(CORS) { anyHost() allowMethod(HttpMethod.Options) allowMethod(HttpMethod.Put) allowMethod(HttpMethod.Delete) allowHeader(HttpHeaders.ContentType) allowHeader(HttpHeaders.Authorization) } } Definindo Rotas O roteamento no Ktor e declarativo e baseado em DSL:\nfun Application.configurarRoteamento() { routing { route(\u0026#34;/api\u0026#34;) { produtoRoutes() categoriaRoutes() } } } fun Route.produtoRoutes() { val service = ProdutoService() route(\u0026#34;/produtos\u0026#34;) { get { val pagina = call.request.queryParameters[\u0026#34;pagina\u0026#34;]?.toIntOrNull() ?: 0 val tamanho = call.request.queryParameters[\u0026#34;tamanho\u0026#34;]?.toIntOrNull() ?: 20 val produtos = service.listarTodos(pagina, tamanho) call.respond(produtos) } get(\u0026#34;/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toLongOrNull() ?: throw ValidacaoException(\u0026#34;ID invalido\u0026#34;) val produto = service.buscarPorId(id) call.respond(produto) } post { val request = call.receive\u0026lt;CriarProdutoRequest\u0026gt;() val produto = service.criar(request) call.respond(HttpStatusCode.Created, produto) } put(\u0026#34;/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toLongOrNull() ?: throw ValidacaoException(\u0026#34;ID invalido\u0026#34;) val request = call.receive\u0026lt;AtualizarProdutoRequest\u0026gt;() val produto = service.atualizar(id, request) call.respond(produto) } delete(\u0026#34;/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;]?.toLongOrNull() ?: throw ValidacaoException(\u0026#34;ID invalido\u0026#34;) service.deletar(id) call.respond(HttpStatusCode.NoContent) } } } Banco de Dados com Exposed Exposed e o framework ORM da JetBrains para Kotlin, com integração natural com Ktor:\n// Definicao da tabela object Produtos : LongIdTable(\u0026#34;produtos\u0026#34;) { val nome = varchar(\u0026#34;nome\u0026#34;, 255) val preco = decimal(\u0026#34;preco\u0026#34;, 10, 2) val descricao = text(\u0026#34;descricao\u0026#34;).nullable() val criadoEm = datetime(\u0026#34;criado_em\u0026#34;).defaultExpression(CurrentDateTime) val categoriaId = reference(\u0026#34;categoria_id\u0026#34;, Categorias).nullable() } // Configuração do banco fun Application.configurarBancoDeDados() { val config = HikariConfig().apply { driverClassName = \u0026#34;org.postgresql.Driver\u0026#34; jdbcUrl = environment.config.property(\u0026#34;database.url\u0026#34;).getString() username = environment.config.property(\u0026#34;database.user\u0026#34;).getString() password = environment.config.property(\u0026#34;database.password\u0026#34;).getString() maximumPoolSize = 10 } val dataSource = HikariDataSource(config) Database.connect(dataSource) transaction { SchemaUtils.create(Produtos, Categorias) } } Camada de Serviço class ProdutoService { suspend fun listarTodos(pagina: Int, tamanho: Int): List\u0026lt;ProdutoResponse\u0026gt; { return dbQuery { Produtos.selectAll() .limit(tamanho, offset = (pagina * tamanho).toLong()) .map { it.toProdutoResponse() } } } suspend fun buscarPorId(id: Long): ProdutoResponse { return dbQuery { Produtos.selectAll().where { Produtos.id eq id } .singleOrNull() ?.toProdutoResponse() ?: throw RecursoNaoEncontradoException(\u0026#34;Produto $id nao encontrado\u0026#34;) } } suspend fun criar(request: CriarProdutoRequest): ProdutoResponse { validar(request) return dbQuery { val id = Produtos.insertAndGetId { it[nome] = request.nome it[preco] = request.preco it[descricao] = request.descricao it[categoriaId] = request.categoriaId } buscarPorIdInterno(id.value) } } suspend fun deletar(id: Long) { dbQuery { val linhasAfetadas = Produtos.deleteWhere { Produtos.id eq id } if (linhasAfetadas == 0) { throw RecursoNaoEncontradoException(\u0026#34;Produto $id nao encontrado\u0026#34;) } } } private fun validar(request: CriarProdutoRequest) { if (request.nome.isBlank()) { throw ValidacaoException(\u0026#34;Nome e obrigatorio\u0026#34;) } if (request.preco \u0026lt;= BigDecimal.ZERO) { throw ValidacaoException(\u0026#34;Preco deve ser positivo\u0026#34;) } } } // Função utilitaria para transacoes assincronas suspend fun \u0026lt;T\u0026gt; dbQuery(bloco: () -\u0026gt; T): T { return newSuspendedTransaction(Dispatchers.IO) { bloco() } } Autenticação com JWT fun Application.configurarAutenticacao() { val segredo = environment.config.property(\u0026#34;jwt.secret\u0026#34;).getString() val emissor = environment.config.property(\u0026#34;jwt.issuer\u0026#34;).getString() val audiencia = environment.config.property(\u0026#34;jwt.audience\u0026#34;).getString() install(Authentication) { jwt(\u0026#34;auth-jwt\u0026#34;) { realm = \u0026#34;Meu App\u0026#34; verifier( JWT.require(Algorithm.HMAC256(segredo)) .withIssuer(emissor) .withAudience(audiencia) .build() ) validate { credential -\u0026gt; if (credential.payload.audience.contains(audiencia)) { JWTPrincipal(credential.payload) } else null } challenge { _, _ -\u0026gt; call.respond( HttpStatusCode.Unauthorized, ErroResponse(401, \u0026#34;Token invalido ou expirado\u0026#34;) ) } } } } // Rotas protegidas fun Route.rotasProtegidas() { authenticate(\u0026#34;auth-jwt\u0026#34;) { get(\u0026#34;/api/perfil\u0026#34;) { val principal = call.principal\u0026lt;JWTPrincipal\u0026gt;() val usuarioId = principal!!.payload.getClaim(\u0026#34;usuario_id\u0026#34;).asLong() val usuario = usuarioService.buscarPorId(usuarioId) call.respond(usuario) } } } // Gerar token fun gerarToken(usuario: Usuario): String { return JWT.create() .withIssuer(emissor) .withAudience(audiencia) .withClaim(\u0026#34;usuario_id\u0026#34;, usuario.id) .withClaim(\u0026#34;email\u0026#34;, usuario.email) .withExpiresAt(Date(System.currentTimeMillis() + 3600000)) .sign(Algorithm.HMAC256(segredo)) } Boas Práticas com Ktor Organize rotas em extension functions: cada recurso deve ter seu próprio arquivo de rotas como extension function de Route. Use injeção de dependência: Koin integra nativamente com Ktor é fácilita testes. Valide entrada manualmente ou com bibliotecas: Ktor não tem válidação embutida como Spring. Use funções de válidação explicitas. Configure logging adequadamente: o Logback e o padrão, configure niveis por pacote para debug eficiente. Aproveite coroutines: todas as rotas do Ktor já são funções suspensas. Use Dispatchers.IO para operações bloqueantes. Use configuração externalizada: o arquivo application.conf permite configurações diferentes por ambiente. Isole dependências rápidas: Redis pode ajudar com cache, sessões e rate limiting, mas deve ficar atrás de serviços próprios para não espalhar chaves e TTLs pelas rotas. Leia o guia de Kotlin com Redis. Erros Comuns e Armadilhas Esquecer o plugin de serialização: sem ContentNegotiation configurado, o Ktor não serializa/deserializa objetos automaticamente. Você recebera erros ao usar call.receive ou call.respond. Bloquear a thread do servidor: operações bloqueantes sem withContext(Dispatchers.IO) travam o event loop do Netty. Nao tratar exceções: sem StatusPages, exceções não tratadas retornam respostas HTML genericas em vez de JSON. Ignorar CORS: clientes web receberao erros se CORS não estiver configurado corretamente. Conexoes de banco não gerenciadas: sempre use um pool de conexoes como HikariCP em vez de conexoes diretas. Conclusão e Próximos Passos O Ktor oferece uma alternativa leve e idiomatica ao Spring Boot para desenvolvimento backend em Kotlin. Sua natureza modular, suporte nativo a coroutines e API baseada em DSL resultam em aplicações performaticas e faceis de entender. Para ir além, explore WebSockets com Ktor para comunicação em tempo real, estude o deploy com Docker, documente contratos com OpenAPI e Swagger no Ktor e confira nossos guias sobre microsserviços e CI/CD para completar sua stack de backend com Kotlin. Para comparar abordagens de backend em outras linguagens, veja como Go constrói APIs com net/http e frameworks como Gin e como Rust oferece performance extrema com Actix e Axum.\n","permalink":"https://kotlin.dev.br/guias/guia-kotlin-backend-ktor/","summary":"\u003cp\u003eO Ktor é o framework web oficial da JetBrains, construido inteiramente em Kotlin e projetado para aproveitar ao maximo os recursos da linguagem, especialmente coroutines. Diferente do Spring Boot, que traz um ecossistema completo e opinado, o Ktor segue uma filosofia minimalista e modular: você instala apenas os plugins que precisa, mantendo a aplicação leve é o startup rápido. Isso o torna ideal para microsserviços, APIs e aplicações que exigem alta performance com baixo consumo de recursos. Neste guia, vamos construir uma API completa com Ktor, cobrindo rotas, serialização, banco de dados, autenticação e deploy.\u003c/p\u003e","title":"Kotlin com Ktor: Guia Completo para Backend | Kotlin Brasil"},{"content":"Neste tutorial completo, você vai aprender a implementar a arquitetura MVVM (Model-View-ViewModel) no Android usando Kotlin. Vamos cobrir ViewModel, LiveData, StateFlow, o Repository pattern, injeção de dependência manual e construir um exemplo prático integrando Room e Retrofit. Ao final, você terá uma base sólida para estruturar seus projetos Android de forma escalável e testável.\nO que é a Arquitetura MVVM? O MVVM divide o código do aplicativo em três camadas com responsabilidades bem definidas:\nModel: camada de dados — inclui o banco de dados local (Room), APIs remotas (Retrofit), é a lógica de negócios View: camada de apresentação — Activities, Fragments e Composables que exibem dados e capturam interações do usuário ViewModel: camada intermediária — prepara e gerencia os dados que a View precisa exibir, sobrevivendo a mudanças de configuração (como rotação de tela) O princípio fundamental é que a View observa o ViewModel, é o ViewModel não conhece a View. Esse desacoplamento facilita os testes unitários e mantém o código organizado conforme o projeto cresce.\nPasso 1: Configurando as Dependências Adicione as dependências no build.gradle.kts:\ndependencies { // ViewModel e LiveData implementation(\u0026#34;androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0\u0026#34;) implementation(\u0026#34;androidx.lifecycle:lifecycle-livedata-ktx:2.7.0\u0026#34;) implementation(\u0026#34;androidx.lifecycle:lifecycle-runtime-ktx:2.7.0\u0026#34;) // Para coletar StateFlow de forma segura implementation(\u0026#34;androidx.lifecycle:lifecycle-runtime-compose:2.7.0\u0026#34;) // Activity KTX (para viewModels() delegate) implementation(\u0026#34;androidx.activity:activity-ktx:1.8.2\u0026#34;) implementation(\u0026#34;androidx.fragment:fragment-ktx:1.6.2\u0026#34;) // Coroutines implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3\u0026#34;) } Passo 2: Criando o Model — Entity e DAO Vamos construir um app de notas para ilustrar a arquitetura. Começamos pela camada de dados:\nimport androidx.room.* import kotlinx.coroutines.flow.Flow @Entity(tableName = \u0026#34;notas\u0026#34;) data class Nota( @PrimaryKey(autoGenerate = true) val id: Long = 0, val titulo: String, val conteudo: String, val dataCriacao: Long = System.currentTimeMillis(), val favorita: Boolean = false ) @Dao interface NotaDao { @Query(\u0026#34;SELECT * FROM notas ORDER BY dataCriacao DESC\u0026#34;) fun observarTodas(): Flow\u0026lt;List\u0026lt;Nota\u0026gt;\u0026gt; @Query(\u0026#34;SELECT * FROM notas WHERE favorita = 1 ORDER BY dataCriacao DESC\u0026#34;) fun observarFavoritas(): Flow\u0026lt;List\u0026lt;Nota\u0026gt;\u0026gt; @Query(\u0026#34;SELECT * FROM notas WHERE id = :id\u0026#34;) suspend fun buscarPorId(id: Long): Nota? @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun inserir(nota: Nota): Long @Update suspend fun atualizar(nota: Nota) @Delete suspend fun deletar(nota: Nota) } Passo 3: O Repository Pattern — Separando as Fontes de Dados O Repository é a camada que abstrai as fontes de dados (local e remota) para o ViewModel. Ele decide de onde buscar os dados e como sincronizá-los:\nclass NotaRepository( private val notaDao: NotaDao, private val apiService: ApiService? = null // fonte remota opcional ) { // Dados reativos do banco local val todasNotas: Flow\u0026lt;List\u0026lt;Nota\u0026gt;\u0026gt; = notaDao.observarTodas() val favoritas: Flow\u0026lt;List\u0026lt;Nota\u0026gt;\u0026gt; = notaDao.observarFavoritas() suspend fun buscarPorId(id: Long): Nota? { return notaDao.buscarPorId(id) } suspend fun salvar(nota: Nota): Long { return notaDao.inserir(nota) } suspend fun atualizar(nota: Nota) { notaDao.atualizar(nota) } suspend fun deletar(nota: Nota) { notaDao.deletar(nota) } suspend fun alternarFavorita(nota: Nota) { notaDao.atualizar(nota.copy(favorita = !nota.favorita)) } // Exemplo de sincronização com API remota suspend fun sincronizar(): Result\u0026lt;Unit\u0026gt; { return try { val notasRemotas = apiService?.buscarNotas() ?: return Result.success(Unit) notaDao.inserirTodas(notasRemotas) Result.success(Unit) } catch (e: Exception) { Result.failure(e) } } } O Repository recebe suas dependências pelo construtor, seguindo o princípio de inversão de dependência. Isso facilita a substituição por implementações de teste (mocks).\nPasso 4: O ViewModel — Gerenciando o Estado da UI O ViewModel é o coração da arquitetura MVVM. Ele expõe o estado da UI e processa ações do usuário:\nimport androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch // Estado da UI representado como uma data class imutável data class NotasUiState( val notas: List\u0026lt;Nota\u0026gt; = emptyList(), val isLoading: Boolean = false, val erro: String? = null, val filtro: FiltroNotas = FiltroNotas.TODAS ) enum class FiltroNotas { TODAS, FAVORITAS } class NotaViewModel( private val repository: NotaRepository ) : ViewModel() { private val _uiState = MutableStateFlow(NotasUiState(isLoading = true)) val uiState: StateFlow\u0026lt;NotasUiState\u0026gt; = _uiState.asStateFlow() private val _filtroAtual = MutableStateFlow(FiltroNotas.TODAS) init { observarNotas() } private fun observarNotas() { viewModelScope.launch { _filtroAtual.flatMapLatest { filtro -\u0026gt; when (filtro) { FiltroNotas.TODAS -\u0026gt; repository.todasNotas FiltroNotas.FAVORITAS -\u0026gt; repository.favoritas } }.collect { notas -\u0026gt; _uiState.update { state -\u0026gt; state.copy( notas = notas, isLoading = false, erro = null ) } } } } fun alterarFiltro(filtro: FiltroNotas) { _filtroAtual.value = filtro _uiState.update { it.copy(filtro = filtro) } } fun adicionarNota(titulo: String, conteudo: String) { viewModelScope.launch { try { repository.salvar(Nota(titulo = titulo, conteudo = conteudo)) } catch (e: Exception) { _uiState.update { it.copy(erro = \u0026#34;Erro ao salvar nota: ${e.message}\u0026#34;) } } } } fun deletarNota(nota: Nota) { viewModelScope.launch { try { repository.deletar(nota) } catch (e: Exception) { _uiState.update { it.copy(erro = \u0026#34;Erro ao deletar nota\u0026#34;) } } } } fun alternarFavorita(nota: Nota) { viewModelScope.launch { repository.alternarFavorita(nota) } } fun limparErro() { _uiState.update { it.copy(erro = null) } } } O ViewModel usa viewModelScope para lançar coroutines que são automaticamente canceladas quando o ViewModel é destruído. O estado é exposto como StateFlow imutável para a View.\nPasso 5: LiveData vs StateFlow no ViewModel Tanto LiveData quanto StateFlow podem ser usados para expor estado. Aqui está a comparação:\n// Abordagem com LiveData class NotaViewModelComLiveData( private val repository: NotaRepository ) : ViewModel() { // LiveData é lifecycle-aware nativamente val notas: LiveData\u0026lt;List\u0026lt;Nota\u0026gt;\u0026gt; = repository.todasNotas .asLiveData() // converte Flow para LiveData private val _erro = MutableLiveData\u0026lt;String?\u0026gt;() val erro: LiveData\u0026lt;String?\u0026gt; = _erro fun adicionarNota(titulo: String, conteudo: String) { viewModelScope.launch { try { repository.salvar(Nota(titulo = titulo, conteudo = conteudo)) } catch (e: Exception) { _erro.value = e.message } } } } // Abordagem com StateFlow (recomendada para projetos novos) class NotaViewModelComStateFlow( private val repository: NotaRepository ) : ViewModel() { val notas: StateFlow\u0026lt;List\u0026lt;Nota\u0026gt;\u0026gt; = repository.todasNotas .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = emptyList() ) } O SharingStarted.WhileSubscribed(5000) mantém o Flow ativo por 5 segundos após o último coletor se desconectar. Isso evita reiniciar a coleta durante rotações de tela, onde a Activity é destruída e recriada rapidamente.\nPasso 6: A View — Conectando Tudo Na Activity ou Fragment, observamos o ViewModel e atualizamos a UI:\nimport android.os.Bundle import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import kotlinx.coroutines.launch class NotasActivity : AppCompatActivity() { private val viewModel: NotaViewModel by viewModels { NotaViewModelFactory( (application as App).notaRepository ) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_notas) // Coleta segura do StateFlow — respeita o lifecycle lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { state -\u0026gt; atualizarUI(state) } } } } private fun atualizarUI(state: NotasUiState) { if (state.isLoading) { // mostrar indicador de carregamento } else { // atualizar a lista no adapter adapter.submitList(state.notas) } state.erro?.let { mensagem -\u0026gt; // exibir Snackbar com o erro Snackbar.make(rootView, mensagem, Snackbar.LENGTH_LONG).show() viewModel.limparErro() } } } O repeatOnLifecycle garante que a coleta é pausada quando a Activity vai para o background e retomada quando volta. Isso evita atualizações desnecessárias e possíveis crashes.\nPasso 7: Injeção de Dependência Manual Sem bibliotecas como Hilt ou Koin, podemos fazer injeção de dependência manualmente usando a classe Application e ViewModelFactory:\nclass App : Application() { // Lazy: instanciado apenas quando necessario private val database by lazy { AppDatabase.getInstance(this) } val notaRepository by lazy { NotaRepository(database.notaDao()) } } class NotaViewModelFactory( private val repository: NotaRepository ) : ViewModelProvider.Factory { override fun \u0026lt;T : ViewModel\u0026gt; create(modelClass: Class\u0026lt;T\u0026gt;): T { if (modelClass.isAssignableFrom(NotaViewModel::class.java)) { @Suppress(\u0026#34;UNCHECKED_CAST\u0026#34;) return NotaViewModel(repository) as T } throw IllegalArgumentException(\u0026#34;ViewModel desconhecido: ${modelClass.name}\u0026#34;) } } Esse padrão funciona bem para projetos pequenos e médios. Para projetos maiores, considere usar Hilt (recomendado pelo Google) ou Koin para gerenciar dependências automaticamente.\nPasso 8: Exemplo Prático — Integrando Room e Retrofit Vamos unir tudo em um Repository que busca dados da API e salva localmente:\nclass NotaRepository( private val notaDao: NotaDao, private val apiService: ApiService ) { val notas: Flow\u0026lt;List\u0026lt;Nota\u0026gt;\u0026gt; = notaDao.observarTodas() // Estratégia: mostrar dados locais e atualizar em background suspend fun atualizarNotas(): Result\u0026lt;Unit\u0026gt; { return try { val notasRemotas = apiService.buscarNotas() notaDao.inserirTodas(notasRemotas) Result.success(Unit) } catch (e: Exception) { // Dados locais continuam disponíveis Result.failure(e) } } suspend fun criarNota(titulo: String, conteudo: String): Result\u0026lt;Nota\u0026gt; { return try { val nota = Nota(titulo = titulo, conteudo = conteudo) // Salva localmente primeiro (offline-first) val id = notaDao.inserir(nota) val notaSalva = nota.copy(id = id) // Tenta sincronizar com o servidor try { apiService.criarNota(notaSalva) } catch (e: Exception) { // Marca para sincronização futura } Result.success(notaSalva) } catch (e: Exception) { Result.failure(e) } } } No ViewModel, integramos tudo:\nclass NotaViewModel(private val repository: NotaRepository) : ViewModel() { private val _uiState = MutableStateFlow(NotasUiState(isLoading = true)) val uiState: StateFlow\u0026lt;NotasUiState\u0026gt; = _uiState.asStateFlow() init { // Observa dados locais viewModelScope.launch { repository.notas.collect { lista -\u0026gt; _uiState.update { it.copy(notas = lista, isLoading = false) } } } // Atualiza do servidor em background sincronizar() } fun sincronizar() { viewModelScope.launch { _uiState.update { it.copy(isLoading = true) } repository.atualizarNotas().onFailure { e -\u0026gt; _uiState.update { it.copy(erro = \u0026#34;Falha ao sincronizar: ${e.message}\u0026#34;) } } _uiState.update { it.copy(isLoading = false) } } } } Erros Comuns Colocar lógica de negócios na View: Activities e Fragments devem apenas observar o estado e delegar ações ao ViewModel. Qualquer lógica de processamento pertence ao ViewModel ou ao Repository.\nViewModel referenciando a View diretamente: O ViewModel nunca deve ter referência a Activities, Fragments ou Views. Isso causa memory leaks e quebra a testabilidade. Use StateFlow ou LiveData para comunicação.\nNão usar repeatOnLifecycle: Coletar StateFlow com lifecycleScope.launch sem repeatOnLifecycle mantém a coleta ativa mesmo com o app em background, desperdiçando recursos.\nEstado mutável exposto publicamente: Sempre exponha StateFlow (imutável) e mantenha MutableStateFlow privado. O mesmo vale para LiveData vs MutableLiveData.\nCriar o ViewModel manualmente: Nunca instancie ViewModels com NotaViewModel(). Use viewModels() ou ViewModelProvider para que o Android gerencie o ciclo de vida corretamente.\nConclusão e Próximos Passos Neste tutorial, você aprendeu a implementar a arquitetura MVVM com Kotlin de forma completa: separação de responsabilidades entre Model, View é ViewModel, uso de StateFlow e LiveData, o Repository pattern para abstração de dados, injeção de dependência manual, e um exemplo prático integrando Room e Retrofit. Para preferências pequenas da tela, como filtros, ordenação e tema, complemente o repository com DataStore Preferences em vez de criar tabelas desnecessárias.\nComo próximos passos, recomendamos:\nEstudar Hilt para injeção de dependência automatizada e escalável Explorar Jetpack Compose para uma camada de View declarativa que se integra perfeitamente com o MVVM Aprender sobre Clean Architecture para projetos de grande escala Praticar testes unitários do ViewModel com kotlinx-coroutines-test Consultar o glossário de Flow e coroutine para reforçar conceitos Revisar Android offline-first com Kotlin para entender como MVVM, Room, DataStore e WorkManager trabalham juntos em apps reais A arquitetura MVVM é o padrão recomendado pelo Google para apps Android e dominar sua implementação é essencial para escrever código limpo, escalável e testável. Padrões arquiteturais semelhantes são adotados em Python com Django e Flask e Go com Clean Architecture.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-mvvm-tutorial/","summary":"\u003cp\u003eNeste tutorial completo, você vai aprender a implementar a arquitetura \u003cstrong\u003eMVVM\u003c/strong\u003e (Model-View-ViewModel) no Android usando Kotlin. Vamos cobrir ViewModel, LiveData, StateFlow, o Repository pattern, injeção de dependência manual e construir um exemplo prático integrando Room e Retrofit. Ao final, você terá uma base sólida para estruturar seus projetos Android de forma escalável e testável.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-a-arquitetura-mvvm\"\u003eO que é a Arquitetura MVVM?\u003c/h2\u003e\n\u003cp\u003eO MVVM divide o código do aplicativo em três camadas com responsabilidades bem definidas:\u003c/p\u003e","title":"MVVM com Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Kotlin e Spring Boot formam uma combinacao poderosa para desenvolvimento backend na JVM. O Spring oferece suporte oficial a Kotlin desde a versão 5, com extensoes dedicadas que aproveitam recursos como null safety, data classes, extension functions e coroutines. Muitas empresas que já usam Spring estao migrando de Java para Kotlin no backend, beneficiando-se de um código mais conciso e seguro sem abrir mao do vasto ecossistema Spring. Este guia cobre desde a configuração inicial até padrões avançados para aplicações em producao.\nConfigurando o Projeto O Spring Initializr (start.spring.io) permite gerar projetos Kotlin com Spring Boot. A configuração no build.gradle.kts inclui plugins específicos:\nplugins { id(\u0026#34;org.springframework.boot\u0026#34;) version \u0026#34;3.2.2\u0026#34; id(\u0026#34;io.spring.dependency-management\u0026#34;) version \u0026#34;1.1.4\u0026#34; kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;1.9.22\u0026#34; kotlin(\u0026#34;plugin.spring\u0026#34;) version \u0026#34;1.9.22\u0026#34; kotlin(\u0026#34;plugin.jpa\u0026#34;) version \u0026#34;1.9.22\u0026#34; } dependencies { implementation(\u0026#34;org.springframework.boot:spring-boot-starter-web\u0026#34;) implementation(\u0026#34;org.springframework.boot:spring-boot-starter-data-jpa\u0026#34;) implementation(\u0026#34;org.springframework.boot:spring-boot-starter-validation\u0026#34;) implementation(\u0026#34;com.fasterxml.jackson.module:jackson-module-kotlin\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlin:kotlin-reflect\u0026#34;) runtimeOnly(\u0026#34;org.postgresql:postgresql\u0026#34;) testImplementation(\u0026#34;org.springframework.boot:spring-boot-starter-test\u0026#34;) } O plugin kotlin-spring adiciona automaticamente o modificador open as classes anotadas com @Component, @Service, @Repository e @Configuration, necessário para os proxies do Spring. O plugin kotlin-jpa gera construtores no-arg para entidades JPA.\nClasse Principal da Aplicação @SpringBootApplication class MeuAppApplication fun main(args: Array\u0026lt;String\u0026gt;) { runApplication\u0026lt;MeuAppApplication\u0026gt;(*args) } A função runApplication e uma extension function do Spring para Kotlin, substituindo o padrão Java SpringApplication.run().\nEntidades JPA com Kotlin Data classes não são ideais para entidades JPA, pois o JPA requer mutabilidade e proxies. A abordagem recomendada:\n@Entity @Table(name = \u0026#34;produtos\u0026#34;) class Produto( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0, @Column(nullable = false) var nome: String, @Column(nullable = false) var preco: BigDecimal, @Column(length = 1000) var descricao: String? = null, @Column(name = \u0026#34;criado_em\u0026#34;) val criadoEm: LocalDateTime = LocalDateTime.now(), @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = \u0026#34;categoria_id\u0026#34;) var categoria: Categoria? = null ) @Entity @Table(name = \u0026#34;categorias\u0026#34;) class Categoria( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0, @Column(nullable = false, unique = true) var nome: String, @OneToMany(mappedBy = \u0026#34;categoria\u0026#34;, cascade = [CascadeType.ALL]) val produtos: MutableList\u0026lt;Produto\u0026gt; = mutableListOf() ) Repositories com Spring Data O Spring Data JPA gera implementacoes automaticamente a partir de interfaces:\ninterface ProdutoRepository : JpaRepository\u0026lt;Produto, Long\u0026gt; { fun findByNomeContainingIgnoreCase(nome: String): List\u0026lt;Produto\u0026gt; fun findByCategoriaId(categoriaId: Long): List\u0026lt;Produto\u0026gt; @Query(\u0026#34;SELECT p FROM Produto p WHERE p.preco BETWEEN :min AND :max\u0026#34;) fun findByFaixaDePreco( @Param(\u0026#34;min\u0026#34;) min: BigDecimal, @Param(\u0026#34;max\u0026#34;) max: BigDecimal ): List\u0026lt;Produto\u0026gt; fun findByNomeContainingIgnoreCase( nome: String, pageable: Pageable ): Page\u0026lt;Produto\u0026gt; } Camada de Serviço A camada de serviço contém a lógica de negócio e coordena operações entre repositories:\n@Service class ProdutoService( private val produtoRepository: ProdutoRepository, private val categoriaRepository: CategoriaRepository ) { fun listarTodos(pageable: Pageable): Page\u0026lt;ProdutoResponse\u0026gt; { return produtoRepository.findAll(pageable).map { it.toResponse() } } fun buscarPorId(id: Long): ProdutoResponse { val produto = produtoRepository.findById(id) .orElseThrow { RecursoNaoEncontradoException(\u0026#34;Produto $id nao encontrado\u0026#34;) } return produto.toResponse() } @Transactional fun criar(request: CriarProdutoRequest): ProdutoResponse { val categoria = request.categoriaId?.let { categoriaRepository.findById(it) .orElseThrow { RecursoNaoEncontradoException(\u0026#34;Categoria $it nao encontrada\u0026#34;) } } val produto = Produto( nome = request.nome, preco = request.preco, descricao = request.descricao, categoria = categoria ) return produtoRepository.save(produto).toResponse() } @Transactional fun atualizar(id: Long, request: AtualizarProdutoRequest): ProdutoResponse { val produto = produtoRepository.findById(id) .orElseThrow { RecursoNaoEncontradoException(\u0026#34;Produto $id nao encontrado\u0026#34;) } request.nome?.let { produto.nome = it } request.preco?.let { produto.preco = it } request.descricao?.let { produto.descricao = it } return produtoRepository.save(produto).toResponse() } @Transactional fun deletar(id: Long) { if (!produtoRepository.existsById(id)) { throw RecursoNaoEncontradoException(\u0026#34;Produto $id nao encontrado\u0026#34;) } produtoRepository.deleteById(id) } } DTOs e Mapeamento Data classes são perfeitas para DTOs de request e response:\ndata class CriarProdutoRequest( @field:NotBlank(message = \u0026#34;Nome e obrigatorio\u0026#34;) val nome: String, @field:Positive(message = \u0026#34;Preco deve ser positivo\u0026#34;) val preco: BigDecimal, val descricao: String? = null, val categoriaId: Long? = null ) data class AtualizarProdutoRequest( val nome: String? = null, val preco: BigDecimal? = null, val descricao: String? = null ) data class ProdutoResponse( val id: Long, val nome: String, val preco: BigDecimal, val descricao: String?, val categoriaNome: String?, val criadoEm: LocalDateTime ) // Extension function para mapeamento fun Produto.toResponse() = ProdutoResponse( id = id, nome = nome, preco = preco, descricao = descricao, categoriaNome = categoria?.nome, criadoEm = criadoEm ) REST Controllers @RestController @RequestMapping(\u0026#34;/api/produtos\u0026#34;) class ProdutoController( private val produtoService: ProdutoService ) { @GetMapping fun listar( @RequestParam(defaultValue = \u0026#34;0\u0026#34;) pagina: Int, @RequestParam(defaultValue = \u0026#34;20\u0026#34;) tamanho: Int, @RequestParam(defaultValue = \u0026#34;nome\u0026#34;) ordenarPor: String ): Page\u0026lt;ProdutoResponse\u0026gt; { val pageable = PageRequest.of(pagina, tamanho, Sort.by(ordenarPor)) return produtoService.listarTodos(pageable) } @GetMapping(\u0026#34;/{id}\u0026#34;) fun buscar(@PathVariable id: Long): ProdutoResponse { return produtoService.buscarPorId(id) } @PostMapping @ResponseStatus(HttpStatus.CREATED) fun criar(@Valid @RequestBody request: CriarProdutoRequest): ProdutoResponse { return produtoService.criar(request) } @PutMapping(\u0026#34;/{id}\u0026#34;) fun atualizar( @PathVariable id: Long, @Valid @RequestBody request: AtualizarProdutoRequest ): ProdutoResponse { return produtoService.atualizar(id, request) } @DeleteMapping(\u0026#34;/{id}\u0026#34;) @ResponseStatus(HttpStatus.NO_CONTENT) fun deletar(@PathVariable id: Long) { produtoService.deletar(id) } } Tratamento Global de Erros @RestControllerAdvice class GlobalExceptionHandler { @ExceptionHandler(RecursoNaoEncontradoException::class) @ResponseStatus(HttpStatus.NOT_FOUND) fun handleRecursoNaoEncontrado(ex: RecursoNaoEncontradoException): ErroResponse { return ErroResponse( status = 404, mensagem = ex.message ?: \u0026#34;Recurso nao encontrado\u0026#34;, timestamp = LocalDateTime.now() ) } @ExceptionHandler(MethodArgumentNotValidException::class) @ResponseStatus(HttpStatus.BAD_REQUEST) fun handleValidacao(ex: MethodArgumentNotValidException): ErroResponse { val erros = ex.bindingResult.fieldErrors.associate { it.field to (it.defaultMessage ?: \u0026#34;Valor invalido\u0026#34;) } return ErroResponse( status = 400, mensagem = \u0026#34;Erro de validação\u0026#34;, detalhes = erros, timestamp = LocalDateTime.now() ) } } data class ErroResponse( val status: Int, val mensagem: String, val detalhes: Map\u0026lt;String, String\u0026gt;? = null, val timestamp: LocalDateTime ) class RecursoNaoEncontradoException(message: String) : RuntimeException(message) Boas Práticas para Kotlin com Spring Boot Use o plugin kotlin-spring: ele evita a necessidade de abrir classes manualmente para proxies do Spring. Prefira constructor injection: o Kotlin facilita isso com parametros no construtor primario. Evite @Autowired em campos. Nao use data classes para entidades JPA: data classes geram equals/hashCode baseados em todos os campos, o que é problematico com lazy loading. Aproveite null safety: use tipos nullable do Kotlin para campos opcionais em vez de Optional do Java. Use extension functions para mapeamento: elas são mais limpas que classes Mapper separadas para conversao entre entidades e DTOs. Configure o Jackson corretamente: o modulo jackson-module-kotlin e essencial para serializar/deserializar data classes corretamente. Trate cache como arquitetura: quando usar Redis para respostas frequentes, sessões ou rate limiting, defina TTL, invalidação e fallback desde o início. Veja o guia de Kotlin com Redis. Erros Comuns e Armadilhas Esquecer o plugin kotlin-jpa: sem ele, entidades JPA sem construtor no-arg causam erros em runtime. Data classes como entidades: o equals e hashCode gerados automaticamente causam problemas com proxies lazy do Hibernate. Nao registrar o modulo Kotlin do Jackson: sem o jackson-module-kotlin, data classes não são deserializadas corretamente, resultando em erros confusos. Usar lateinit sem necessidade: em Spring, constructor injection elimina a necessidade de lateinit var na maioria dos casos. Ignorar paginação: retornar listas completas em endpoints sem paginação pode causar problemas serios de performance com tabelas grandes. Conclusão e Próximos Passos Kotlin com Spring Boot oferece uma experiência de desenvolvimento backend produtiva e robusta. A combinacao do ecossistema maduro do Spring com a expressividade do Kotlin resulta em aplicações mais seguras e concisas. Para ir além, explore Spring Security para autenticação, WebFlux com coroutines para aplicações reativas e consulte nossos guias sobre testes, Docker e microsserviços para completar sua stack de desenvolvimento. Também vale a pena conhecer como outras linguagens abordam o backend: Go com seu ecossistema minimalista e performático e Python com Django e FastAPI são alternativas populares no mercado brasileiro.\n","permalink":"https://kotlin.dev.br/guias/guia-kotlin-backend-spring/","summary":"\u003cp\u003eKotlin e Spring Boot formam uma combinacao poderosa para desenvolvimento backend na JVM. O Spring oferece suporte oficial a Kotlin desde a versão 5, com extensoes dedicadas que aproveitam recursos como null safety, data classes, extension functions e coroutines. Muitas empresas que já usam Spring estao migrando de Java para Kotlin no backend, beneficiando-se de um código mais conciso e seguro sem abrir mao do vasto ecossistema Spring. Este guia cobre desde a configuração inicial até padrões avançados para aplicações em producao.\u003c/p\u003e","title":"Kotlin com Spring Boot: Guia Completo para Backend | Kotlin Brasil"},{"content":"Kotlin no backend não é mais novidade, e realidade consolidada. Em 2026, cada vez mais empresas estao escolhendo Kotlin como linguagem principal para seus serviços server-side, aproveitando a robustez da JVM com a expressividade moderna da linguagem. Vamos explorar o estado atual e as melhores práticas para desenvolvimento backend com Kotlin.\nPor Que Kotlin no Backend A migração de Java para Kotlin no backend segue acelerando, competindo com linguagens como Go e Python por espaço no backend moderno. Os motivos são claros:\nMenos boilerplate: Data classes, extension functions e scope functions reduzem drasticamente a quantidade de código Null safety: Elimina a classe mais comum de bugs em producao Coroutines: Programação assíncrona sem callback hell Interoperabilidade total: Use qualquer biblioteca Java sem atrito Comunidade crescente: Mais recursos, mais bibliotecas, mais suporte Frameworks Principais Spring Boot com Kotlin Spring Boot continua sendo o framework mais usado para Kotlin no backend enterprise. A integração e de primeira classe:\n@SpringBootApplication class Application fun main(args: Array\u0026lt;String\u0026gt;) { runApplication\u0026lt;Application\u0026gt;(*args) } // Service com coroutines @Service class PedidoService( private val pedidoRepository: PedidoRepository, private val estoqueService: EstoqueService, private val eventPublisher: ApplicationEventPublisher ) { @Transactional suspend fun criarPedido(request: CriarPedidoRequest): Pedido { // Validar estoque val itensValidados = request.itens.map { item -\u0026gt; val disponivel = estoqueService.verificarDisponibilidade( item.produtoId, item.quantidade ) require(disponivel) { \u0026#34;Produto ${item.produtoId} sem estoque suficiente\u0026#34; } item } // Criar pedido val pedido = Pedido( clienteId = request.clienteId, itens = itensValidados.map { it.toItemPedido() }, status = PedidoStatus.CRIADO, criadoEm = Instant.now() ) val salvo = pedidoRepository.save(pedido) // Publicar evento eventPublisher.publishEvent(PedidoCriadoEvent(salvo)) return salvo } } Spring Boot com Kotlin oferece:\nSuporte nativo a coroutines com Spring WebFlux DSL para configuração de beans e rotas Integration testing simplificado Ecossistema maduro com Spring Security, Spring Data, Spring Cloud Ktor Ktor e o framework nativo Kotlin da JetBrains, ideal para microsserviços leves e APIs de alta performance:\nfun main() { embeddedServer(Netty, port = 8080) { configurarApp() }.start(wait = true) } fun Application.configurarApp() { install(ContentNegotiation) { json(Json { prettyPrint = true ignoreUnknownKeys = true encodeDefaults = true }) } install(Authentication) { jwt(\u0026#34;auth\u0026#34;) { realm = \u0026#34;api\u0026#34; verifier(JwtConfig.verifier) validate { credential -\u0026gt; if (credential.payload.audience.contains(\u0026#34;api\u0026#34;)) { JWTPrincipal(credential.payload) } else null } } } install(RateLimit) { register(RateLimitName(\u0026#34;public\u0026#34;)) { rateLimiter(limit = 50, refillPeriod = 60.seconds) } } configurarRotas() } fun Application.configurarRotas() { routing { authenticate(\u0026#34;auth\u0026#34;) { route(\u0026#34;/api/v1\u0026#34;) { pedidoRoutes() produtoRoutes() usuarioRoutes() } } rateLimit(RateLimitName(\u0026#34;public\u0026#34;)) { get(\u0026#34;/health\u0026#34;) { call.respond(mapOf(\u0026#34;status\u0026#34; to \u0026#34;healthy\u0026#34;, \u0026#34;version\u0026#34; to \u0026#34;1.0.0\u0026#34;)) } } } } Ktor se destaca por ser:\nExtremamente leve e rápido para iniciar 100% Kotlin, sem dependências Java legadas Modular (você instala apenas o que precisa) Ideal para microsserviços e serverless Patterns e Arquitetura Clean Architecture com Kotlin // Domain Layer - Puro Kotlin, sem dependências de framework data class Produto( val id: ProdutoId, val nome: String, val descricao: String, val preco: Money, val categoria: Categoria, val ativo: Boolean = true ) { fun aplicarDesconto(percentual: Double): Produto { require(percentual in 0.0..100.0) { \u0026#34;Percentual invalido\u0026#34; } return copy(preco = preco.multiply(1 - percentual / 100)) } } @JvmInline value class ProdutoId(val value: String) @JvmInline value class Money(val centavos: Long) { fun multiply(fator: Double): Money { return Money((centavos * fator).toLong()) } fun toReais(): Double = centavos / 100.0 } // Use Case class CriarProdutoUseCase( private val repository: ProdutoRepository, private val validator: ProdutoValidator ) { suspend operator fun invoke(command: CriarProdutoCommand): Result\u0026lt;Produto\u0026gt; { return runCatching { validator.validar(command) val produto = command.toProduto() repository.salvar(produto) } } } Repository Pattern com Exposed Exposed e o ORM nativo Kotlin da JetBrains, com DSL type-safe:\n// Definicao de tabela object Produtos : Table(\u0026#34;produtos\u0026#34;) { val id = varchar(\u0026#34;id\u0026#34;, 36) val nome = varchar(\u0026#34;nome\u0026#34;, 255) val descricao = text(\u0026#34;descricao\u0026#34;) val precoCentavos = long(\u0026#34;preco_centavos\u0026#34;) val categoria = varchar(\u0026#34;categoria\u0026#34;, 50) val ativo = bool(\u0026#34;ativo\u0026#34;).default(true) val criadoEm = datetime(\u0026#34;criado_em\u0026#34;) val atualizadoEm = datetime(\u0026#34;atualizado_em\u0026#34;) override val primaryKey = PrimaryKey(id) } class ProdutoRepositoryImpl( private val database: Database ) : ProdutoRepository { override suspend fun buscarPorCategoria( categoria: Categoria, pagina: Int, tamanho: Int ): List\u0026lt;Produto\u0026gt; = dbQuery { Produtos .select { Produtos.categoria eq categoria.name } .orderBy(Produtos.nome) .limit(tamanho, offset = ((pagina - 1) * tamanho).toLong()) .map { it.toProduto() } } override suspend fun salvar(produto: Produto): Produto = dbQuery { Produtos.upsert { it[id] = produto.id.value it[nome] = produto.nome it[descricao] = produto.descricao it[precoCentavos] = produto.preco.centavos it[categoria] = produto.categoria.name it[ativo] = produto.ativo it[atualizadoEm] = LocalDateTime.now() } produto } private suspend fun \u0026lt;T\u0026gt; dbQuery(block: suspend () -\u0026gt; T): T { return newSuspendedTransaction(Dispatchers.IO, database) { block() } } } Testes no Backend Kotlin Kotlin torna testes mais expressivos e menos verbosos:\nclass PedidoServiceTest { private val pedidoRepository = mockk\u0026lt;PedidoRepository\u0026gt;() private val estoqueService = mockk\u0026lt;EstoqueService\u0026gt;() private val service = PedidoService(pedidoRepository, estoqueService) @Test fun `deve criar pedido quando estoque disponivel`() = runTest { // Given val request = criarPedidoRequest() coEvery { estoqueService.verificarDisponibilidade(any(), any()) } returns true coEvery { pedidoRepository.save(any()) } answers { firstArg() } // When val resultado = service.criarPedido(request) // Then assertThat(resultado.status).isEqualTo(PedidoStatus.CRIADO) assertThat(resultado.itens).hasSize(request.itens.size) coVerify { estoqueService.verificarDisponibilidade(any(), any()) } } @Test fun `deve rejeitar pedido quando sem estoque`() = runTest { val request = criarPedidoRequest() coEvery { estoqueService.verificarDisponibilidade(any(), any()) } returns false assertThrows\u0026lt;IllegalArgumentException\u0026gt; { service.criarPedido(request) } } } Performance e Observabilidade Kotlin no backend se beneficia de toda a infraestrutura de observabilidade da JVM:\n// Métricas com Micrometer @RestController class MetricsController( private val meterRegistry: MeterRegistry ) { private val requestCounter = meterRegistry.counter(\u0026#34;api.requests.total\u0026#34;) private val requestTimer = meterRegistry.timer(\u0026#34;api.requests.duration\u0026#34;) @GetMapping(\u0026#34;/api/dados\u0026#34;) suspend fun getDados(): ResponseEntity\u0026lt;DadosResponse\u0026gt; { return requestTimer.recordSuspend { requestCounter.increment() val dados = service.buscarDados() ResponseEntity.ok(dados) } } } Mercado e Oportunidades O mercado para Kotlin backend no Brasil esta em forte crescimento. Bancos como Itau, Nubank e Inter usam Kotlin extensivamente. Fintechs, e-commerces e empresas de tecnologia estao migrando de Java para Kotlin ou iniciando projetos greenfield diretamente em Kotlin.\nAs principais vantagens para empresas que adotam Kotlin no backend incluem reducao de bugs em producao (gracas ao null safety), maior produtividade dos desenvolvedores é fácilidade de contratar (desenvolvedores Java podem migrar para Kotlin rapidamente).\nConclusão Kotlin no backend em 2026 e uma escolha madura e confiavel. Com frameworks como Spring Boot e Ktor, ferramentas excelentes, performance da JVM e uma comunidade ativa, não faltam motivos para adotar Kotlin em seus projetos server-side.\nSe você já trabalha com Java no backend, a migração para Kotlin e gradual e indolor. Se esta comecando do zero, Kotlin oferece tudo que você precisa para construir serviços robustos, escalaveis e mantenveis. Para microsserviços que exigem baixo consumo de memória e startup instantâneo, vale considerar também Go ou Rust como complementos ao seu stack. O futuro do backend na JVM fala Kotlin.\n","permalink":"https://kotlin.dev.br/blog/kotlin-server-side-2026/","summary":"\u003cp\u003eKotlin no backend não é mais novidade, e realidade consolidada. Em 2026, cada vez mais empresas estao escolhendo Kotlin como linguagem principal para seus serviços server-side, aproveitando a robustez da JVM com a expressividade moderna da linguagem. Vamos explorar o estado atual e as melhores práticas para desenvolvimento backend com Kotlin.\u003c/p\u003e\n\u003ch2 id=\"por-que-kotlin-no-backend\"\u003ePor Que Kotlin no Backend\u003c/h2\u003e\n\u003cp\u003eA migração de Java para Kotlin no backend segue acelerando, competindo com linguagens como \u003ca href=\"https://golang.com.br/\" target=\"_blank\" rel=\"noopener\" onclick=\"umami.track('portfolio-site-click', { destination: 'golang.com.br' })\"\u003eGo\u003c/a\u003e e \u003ca href=\"https://python.dev.br/\" target=\"_blank\" rel=\"noopener\" onclick=\"umami.track('portfolio-site-click', { destination: 'python.dev.br' })\"\u003ePython\u003c/a\u003e por espaço no backend moderno. Os motivos são claros:\u003c/p\u003e","title":"Kotlin no Backend em 2026: Guia Completo Server-Side | Kotlin Brasil"},{"content":"Neste tutorial, você vai aprender a usar Retrofit com Kotlin para consumir APIs REST no Android em 2026. Vamos cobrir desde a configuração inicial até decisões de produção: integração com coroutines, OkHttp, interceptors, autenticação, tratamento robusto de erros, cache local, integração com repository e cuidados para apps que precisam funcionar em redes instáveis.\nRetrofit continua aparecendo em vagas Android porque resolve um problema central: transformar contratos HTTP em interfaces Kotlin testáveis. Em projetos reais, porém, não basta criar uma interface e chamar api.buscarDados(). O app precisa lidar com timeout, token expirado, resposta vazia, erro 401, retry, paginação, logs sem dados sensíveis e sincronização com Room ou DataStore. Este guia atualiza o tutorial para essa realidade.\nO que é o Retrofit? O Retrofit é uma biblioteca da Square que transforma interfaces Kotlin/Java em clientes HTTP. Você define os endpoints da API como métodos de uma interface, é o Retrofit gera automaticamente a implementação. Ele trabalha em conjunto com o OkHttp para gerenciar as requisições e com conversores como Gson ou Moshi para serializar/desserializar JSON.\nPasso 1: Configurando as Dependências Adicione as dependências no build.gradle.kts:\ndependencies { // Retrofit implementation(\u0026#34;com.squareup.retrofit2:retrofit:2.11.0\u0026#34;) // Conversor Gson (opção 1) implementation(\u0026#34;com.squareup.retrofit2:converter-gson:2.11.0\u0026#34;) // OU Conversor Moshi (opção 2 — recomendado para Kotlin) implementation(\u0026#34;com.squareup.retrofit2:converter-moshi:2.11.0\u0026#34;) implementation(\u0026#34;com.squareup.moshi:moshi-kotlin:1.15.0\u0026#34;) ksp(\u0026#34;com.squareup.moshi:moshi-kotlin-codegen:1.15.0\u0026#34;) // OkHttp Logging Interceptor implementation(\u0026#34;com.squareup.okhttp3:logging-interceptor:4.12.0\u0026#34;) // Coroutines implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1\u0026#34;) } Não esqueça de adicionar a permissão de internet no AndroidManifest.xml:\n// No AndroidManifest.xml, adicione: // \u0026lt;uses-permission android:name=\u0026#34;android.permission.INTERNET\u0026#34; /\u0026gt; Passo 2: Definindo os Modelos de Dados Vamos criar os modelos para uma API de posts (como a JSONPlaceholder). Com Moshi, usamos a anotação @JsonClass:\nimport com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class Post( val id: Int, @Json(name = \u0026#34;user_id\u0026#34;) val userId: Int, val title: String, val body: String ) @JsonClass(generateAdapter = true) data class Usuario( val id: Int, val name: String, val email: String, @Json(name = \u0026#34;phone\u0026#34;) val telefone: String ) // Com Gson, basta usar @SerializedName: // data class Post( // val id: Int, // @SerializedName(\u0026#34;user_id\u0026#34;) val userId: Int, // val title: String, // val body: String // ) A vantagem do Moshi com codegen é que ele gera adapters em tempo de compilação, evitando reflexão em runtime, o que resulta em melhor performance e compatibilidade com ProGuard/R8. Gson ainda funciona, mas Moshi ou kotlinx.serialization costumam combinar melhor com modelos Kotlin imutáveis, campos nulos explícitos e projetos que usam R8 de forma agressiva.\nPasso 3: Definindo a Interface da API Crie uma interface com os endpoints da API. Com Kotlin e Coroutines, os métodos podem ser suspend:\nimport retrofit2.Response import retrofit2.http.* interface ApiService { @GET(\u0026#34;posts\u0026#34;) suspend fun listarPosts(): List\u0026lt;Post\u0026gt; @GET(\u0026#34;posts/{id}\u0026#34;) suspend fun buscarPost(@Path(\u0026#34;id\u0026#34;) id: Int): Post @GET(\u0026#34;posts\u0026#34;) suspend fun buscarPostsPorUsuario( @Query(\u0026#34;userId\u0026#34;) userId: Int ): List\u0026lt;Post\u0026gt; @GET(\u0026#34;posts\u0026#34;) suspend fun buscarPostsPaginados( @Query(\u0026#34;_page\u0026#34;) pagina: Int, @Query(\u0026#34;_limit\u0026#34;) limite: Int = 20 ): Response\u0026lt;List\u0026lt;Post\u0026gt;\u0026gt; // Response para acessar headers e código HTTP @POST(\u0026#34;posts\u0026#34;) suspend fun criarPost(@Body post: Post): Post @PUT(\u0026#34;posts/{id}\u0026#34;) suspend fun atualizarPost( @Path(\u0026#34;id\u0026#34;) id: Int, @Body post: Post ): Post @PATCH(\u0026#34;posts/{id}\u0026#34;) suspend fun atualizarParcialmente( @Path(\u0026#34;id\u0026#34;) id: Int, @Body campos: Map\u0026lt;String, @JvmSuppressWildcards Any\u0026gt; ): Post @DELETE(\u0026#34;posts/{id}\u0026#34;) suspend fun deletarPost(@Path(\u0026#34;id\u0026#34;) id: Int): Response\u0026lt;Unit\u0026gt; @GET(\u0026#34;users/{id}\u0026#34;) suspend fun buscarUsuario( @Path(\u0026#34;id\u0026#34;) id: Int, @Header(\u0026#34;Authorization\u0026#34;) token: String ): Usuario } As anotações @GET, @POST, @PUT, @DELETE definem o método HTTP. @Path substitui variáveis na URL, @Query adiciona parâmetros de query string, @Body envia o corpo da requisição, e @Header adiciona cabeçalhos específicos.\nPasso 4: Configurando o Retrofit com OkHttp Agora criamos a instância do Retrofit com todas as configurações necessárias:\nimport com.squareup.moshi.Moshi import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit import retrofit2.converter.moshi.MoshiConverterFactory import java.util.concurrent.TimeUnit object RetrofitClient { private const val BASE_URL = \u0026#34;https://jsonplaceholder.typicode.com/\u0026#34; // Configuração do Moshi private val moshi = Moshi.Builder() .addLast(KotlinJsonAdapterFactory()) .build() // Logging Interceptor — mostra requisições no Logcat private val loggingInterceptor = HttpLoggingInterceptor().apply { level = if (BuildConfig.DEBUG) { HttpLoggingInterceptor.Level.BODY } else { HttpLoggingInterceptor.Level.NONE } } // Configuração do OkHttp private val okHttpClient = OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .build() // Instância do Retrofit private val retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .client(okHttpClient) .addConverterFactory(MoshiConverterFactory.create(moshi)) .build() val apiService: ApiService = retrofit.create(ApiService::class.java) } O HttpLoggingInterceptor com nível BODY mostra URLs, headers e corpo das requisições e respostas no Logcat — extremamente útil durante o desenvolvimento. Em produção, use NONE para não expor dados sensíveis.\nEm apps profissionais, também vale configurar timeouts menores para telas interativas e maiores para uploads ou downloads. Um feed pode falhar rápido e mostrar dados locais; um upload de foto talvez precise de outra estratégia. Não trate todos os endpoints como se tivessem o mesmo custo para o usuário.\nPasso 5: Interceptors Personalizados Interceptors do OkHttp permitem modificar todas as requisições de forma centralizada. Isso é muito útil para adicionar headers de autenticação:\nimport okhttp3.Interceptor import okhttp3.Response class AuthInterceptor( private val tokenProvider: () -\u0026gt; String? ) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() val token = tokenProvider() if (token == null) { return chain.proceed(originalRequest) } val requestComAuth = originalRequest.newBuilder() .header(\u0026#34;Authorization\u0026#34;, \u0026#34;Bearer $token\u0026#34;) .header(\u0026#34;Accept\u0026#34;, \u0026#34;application/json\u0026#34;) .build() return chain.proceed(requestComAuth) } } // Interceptor para retry automático class RetryInterceptor(private val maxRetries: Int = 3) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { var tentativa = 0 var response: Response? = null while (tentativa \u0026lt; maxRetries) { try { response?.close() response = chain.proceed(chain.request()) if (response.isSuccessful) return response } catch (e: Exception) { if (tentativa == maxRetries - 1) throw e } tentativa++ } return response ?: throw IllegalStateException(\u0026#34;Todas as tentativas falharam\u0026#34;) } } // Adicione os interceptors ao OkHttpClient: val okHttpClient = OkHttpClient.Builder() .addInterceptor(AuthInterceptor { SessionManager.getToken() }) .addInterceptor(loggingInterceptor) // logging sempre por último .build() Para tokens OAuth2 com refresh automático, evite fazer a renovação dentro de qualquer interceptor sem controle. O OkHttp oferece Authenticator, que roda quando o servidor responde 401 e permite tentar uma nova requisição com token renovado. Isso reduz duplicação e evita que cada repository precise conhecer detalhes de autenticação:\nclass TokenAuthenticator( private val sessao: SessaoRepository, ) : Authenticator { override fun authenticate(route: Route?, response: Response): Request? { if (responseCount(response) \u0026gt;= 2) return null val novoToken = runBlocking { sessao.renovarTokenSePossivel() } ?: return null return response.request.newBuilder() .header(\u0026#34;Authorization\u0026#34;, \u0026#34;Bearer $novoToken\u0026#34;) .build() } private fun responseCount(response: Response): Int { var count = 1 var prior = response.priorResponse while (prior != null) { count++ prior = prior.priorResponse } return count } } O exemplo usa runBlocking porque a API do OkHttp é síncrona. Em produção, mantenha esse caminho curto, protegido contra deadlock e sem chamadas desnecessárias. Se o refresh token falhar, retorne null, limpe a sessão no repository e deixe a UI conduzir o usuário para login.\nPasso 6: Tratamento Robusto de Erros Requisições HTTP podem falhar de diversas formas. Vamos criar uma estrutura robusta para lidar com esses cenários:\nsealed class Resultado\u0026lt;out T\u0026gt; { data class Sucesso\u0026lt;T\u0026gt;(val dados: T) : Resultado\u0026lt;T\u0026gt;() data class Erro(val mensagem: String, val codigo: Int? = null) : Resultado\u0026lt;Nothing\u0026gt;() data object Carregando : Resultado\u0026lt;Nothing\u0026gt;() } suspend fun \u0026lt;T\u0026gt; chamarApi(chamada: suspend () -\u0026gt; T): Resultado\u0026lt;T\u0026gt; { return try { Resultado.Sucesso(chamada()) } catch (e: retrofit2.HttpException) { val mensagem = when (e.code()) { 400 -\u0026gt; \u0026#34;Requisição inválida\u0026#34; 401 -\u0026gt; \u0026#34;Não autorizado — faça login novamente\u0026#34; 403 -\u0026gt; \u0026#34;Acesso negado\u0026#34; 404 -\u0026gt; \u0026#34;Recurso não encontrado\u0026#34; 500 -\u0026gt; \u0026#34;Erro interno do servidor\u0026#34; else -\u0026gt; \u0026#34;Erro HTTP: ${e.code()}\u0026#34; } Resultado.Erro(mensagem, e.code()) } catch (e: java.net.UnknownHostException) { Resultado.Erro(\u0026#34;Sem conexão com a internet\u0026#34;) } catch (e: java.net.SocketTimeoutException) { Resultado.Erro(\u0026#34;Tempo de conexão esgotado\u0026#34;) } catch (e: Exception) { Resultado.Erro(\u0026#34;Erro inesperado: ${e.localizedMessage}\u0026#34;) } } Esse wrapper é suficiente para tutoriais, mas apps maiores normalmente separam erro de rede, erro de autenticação, erro de validação e erro inesperado. Assim, a UI consegue tomar decisões melhores: mostrar botão de tentar novamente, pedir login, destacar campo inválido ou exibir dados em cache. A regra prática é não perder informação cedo demais.\nUma versão mais expressiva pode incluir uma hierarquia de falhas:\nsealed interface FalhaApi { data object SemInternet : FalhaApi data object Timeout : FalhaApi data object NaoAutorizado : FalhaApi data class Http(val codigo: Int, val corpo: String?) : FalhaApi data class Parsing(val detalhe: String?) : FalhaApi } Essa modelagem conversa bem com sealed classes e com estado de tela em MVVM. Em vez de espalhar try/catch pela Activity, concentre a tradução no data source ou repository.\nUsando no Repository:\nclass PostRepository(private val api: ApiService) { suspend fun listarPosts(): Resultado\u0026lt;List\u0026lt;Post\u0026gt;\u0026gt; { return chamarApi { api.listarPosts() } } suspend fun buscarPost(id: Int): Resultado\u0026lt;Post\u0026gt; { return chamarApi { api.buscarPost(id) } } suspend fun criarPost(post: Post): Resultado\u0026lt;Post\u0026gt; { return chamarApi { api.criarPost(post) } } } E no ViewModel:\nclass PostViewModel(private val repository: PostRepository) : ViewModel() { private val _posts = MutableStateFlow\u0026lt;Resultado\u0026lt;List\u0026lt;Post\u0026gt;\u0026gt;\u0026gt;(Resultado.Carregando) val posts: StateFlow\u0026lt;Resultado\u0026lt;List\u0026lt;Post\u0026gt;\u0026gt;\u0026gt; = _posts.asStateFlow() fun carregarPosts() { viewModelScope.launch { _posts.value = Resultado.Carregando _posts.value = repository.listarPosts() } } } Passo 7: Trabalhando com Response para Metadados Às vezes você precisa acessar headers, códigos de status ou verificar se a resposta foi bem-sucedida. Use Response\u0026lt;T\u0026gt;:\nsuspend fun carregarPostsPaginados(pagina: Int): Resultado\u0026lt;List\u0026lt;Post\u0026gt;\u0026gt; { return try { val response = api.buscarPostsPaginados(pagina) if (response.isSuccessful) { val totalPaginas = response.headers()[\u0026#34;X-Total-Count\u0026#34;]?.toIntOrNull() val posts = response.body() ?: emptyList() Resultado.Sucesso(posts) } else { val errorBody = response.errorBody()?.string() Resultado.Erro(\u0026#34;Erro: ${response.code()} - $errorBody\u0026#34;, response.code()) } } catch (e: Exception) { Resultado.Erro(\u0026#34;Falha na requisição: ${e.message}\u0026#34;) } } Retrofit, Room e cache offline Uma tela Android moderna raramente deve depender apenas da resposta imediata da API. Em conexões móveis instáveis, o melhor desenho é fazer a UI observar dados locais e deixar o repository decidir quando buscar rede. Essa é a base de uma arquitetura Android offline-first com Kotlin.\nUm fluxo comum fica assim:\nclass ProdutosRepository( private val api: ProdutosApi, private val dao: ProdutoDao, ) { fun observarProdutos(): Flow\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt; = dao.observarTodos().map { entidades -\u0026gt; entidades.map { it.toDomain() } } suspend fun atualizarProdutos() { val remotos = api.listarProdutos() dao.substituirTodos(remotos.map { it.toEntity() }) } } Nesse modelo, a tela não precisa saber se os dados vieram da internet ou do banco local. Ela observa o Flow do Room e chama atualizarProdutos() em momentos controlados: pull-to-refresh, abertura da tela, retorno de conectividade ou execução em background com WorkManager. O usuário vê dados disponíveis rapidamente, enquanto a sincronização acontece sem bloquear a experiência.\nPara cache HTTP puro, OkHttp também oferece cache de resposta, mas ele não substitui persistência local de produto. Use cache HTTP para reduzir chamadas repetidas quando os headers do servidor ajudam. Use Room quando a experiência precisa continuar funcionando, quando há filtros locais, favoritos, fila de operações pendentes ou estado que precisa sobreviver a limpeza de memória.\nPaginação, retry e limites práticos APIs reais crescem. Em vez de baixar tudo de uma vez, use paginação por página, cursor ou nextToken. Retrofit não impõe um padrão; você modela o contrato:\ndata class PaginaProdutos( val itens: List\u0026lt;ProdutoDto\u0026gt;, val proximoCursor: String?, ) interface ProdutosApi { @GET(\u0026#34;produtos\u0026#34;) suspend fun listarProdutos( @Query(\u0026#34;cursor\u0026#34;) cursor: String? = null, @Query(\u0026#34;limite\u0026#34;) limite: Int = 30, ): PaginaProdutos } Retry também precisa de critério. Não faça retry automático para qualquer erro dentro de um interceptor genérico. Erros 408, 429 e 5xx podem ser temporários; 400, 401, 403 e 404 geralmente exigem ação diferente. Para operações com efeito colateral, como criar pedido ou confirmar pagamento, use chave idempotente antes de repetir chamada. Sem isso, uma tentativa duplicada pode criar dados duplicados no servidor.\nQuando o backend informa Retry-After, respeite esse header. Se a API aplica rate limiting, insistir imediatamente piora a experiência e pode bloquear o usuário por mais tempo.\nSegurança e observabilidade Retrofit e OkHttp facilitam logs, mas logs podem vazar token, CPF, email, endereço ou payload sensível. Em debug, BODY ajuda. Em produção, prefira logs estruturados sem corpo de resposta, com request id, endpoint lógico, status HTTP, duração e tipo de falha. Se o backend devolve um header como X-Request-Id, propague esse valor para facilitar investigação.\nTambém vale padronizar headers:\nclass AppHeadersInterceptor( private val versaoApp: String, ) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request().newBuilder() .header(\u0026#34;Accept\u0026#34;, \u0026#34;application/json\u0026#34;) .header(\u0026#34;X-App-Version\u0026#34;, versaoApp) .build() return chain.proceed(request) } } Esse tipo de header ajuda o backend a diagnosticar bugs por versão, bloquear clientes antigos com mais clareza e correlacionar falhas. Para autenticação mais profunda no servidor, veja também Spring Security com Kotlin, JWT e OAuth2. No app, complemente isso com uma política explícita de segurança de dados locais no Android para tokens, cache HTTP, logs e logout.\nErros Comuns Não usar suspend nos métodos da interface: Sem a palavra-chave suspend, o Retrofit retorna Call\u0026lt;T\u0026gt; em vez de executar diretamente com coroutines. Sempre use suspend para integração com coroutines.\nFazer requisições na Main Thread: Mesmo com coroutines, certifique-se de que o Dispatcher correto está sendo usado. O viewModelScope usa Dispatchers.Main por padrão, mas o Retrofit já muda internamente para uma thread de I/O.\nNão fechar o Response.errorBody(): O errorBody() é um recurso que precisa ser lido uma única vez. Leia-o imediatamente e armazene o resultado se precisar usá-lo depois.\nEsquecer o logging interceptor em debug: Sem o HttpLoggingInterceptor, debugar problemas de API é muito mais difícil. Configure-o em modo BODY durante o desenvolvimento.\nURL base sem barra final: A BASE_URL deve sempre terminar com /. Caso contrário, o Retrofit pode construir URLs incorretas ao combinar com os paths dos endpoints.\nNão tratar diferentes tipos de erro: Tratar todos os erros como genéricos dificulta a experiência do usuário. Diferencie entre erros de rede, erros HTTP e erros de parsing.\nColocar regra de negócio no interceptor: interceptor deve cuidar de transporte, headers e autenticação transversal. Regra de produto pertence ao repository, use case ou camada de domínio.\nConfiar apenas na API para telas críticas: se a tela precisa abrir em rede ruim, combine Retrofit com Room, Flow e estratégia offline-first.\nFazer retry de POST sem idempotência: repetir uma operação de escrita pode duplicar pedido, mensagem ou transação. Use identificador idempotente ou confirme o estado antes de reenviar.\nLogar dados sensíveis: logging de corpo em produção pode expor tokens e informações pessoais. Restrinja logs detalhados ao debug.\nConclusão e Próximos Passos Neste tutorial, você aprendeu a utilizar Retrofit com Kotlin de forma completa e profissional: configuração com Gson ou Moshi, definição de interfaces de API com suporte a coroutines, OkHttp, interceptors personalizados, autenticação, tratamento robusto de erros com sealed classes, acesso a metadados HTTP, cache offline com Room e cuidados de produção.\nComo próximos passos, recomendamos:\nIntegrar Retrofit com Room Database para cache offline de dados Implementar a arquitetura MVVM completa com Repository pattern Explorar Kotlin Flow para transformar respostas de API em streams reativos Estudar Android offline-first com Kotlin para sincronização resiliente Usar WorkManager com Kotlin para retry em background quando a rede voltar Consultar o glossário de interface e coroutine para reforçar conceitos Estudar autenticação OAuth2 com refresh token automático usando interceptors O Retrofit combinado com Kotlin e Coroutines oferece uma experiência de desenvolvimento moderna e eficiente para qualquer projeto Android que precise consumir APIs REST. Para desenvolvimento de APIs no servidor, considere também Go para APIs de alta performance e Python com FastAPI para prototipagem rápida.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-retrofit-tutorial/","summary":"\u003cp\u003eNeste tutorial, você vai aprender a usar \u003cstrong\u003eRetrofit com Kotlin\u003c/strong\u003e para consumir APIs REST no Android em 2026. Vamos cobrir desde a configuração inicial até decisões de produção: integração com \u003ca href=\"/glossario/coroutine/\"\u003ecoroutines\u003c/a\u003e, OkHttp, interceptors, autenticação, tratamento robusto de erros, cache local, integração com repository e cuidados para apps que precisam funcionar em redes instáveis.\u003c/p\u003e\n\u003cp\u003eRetrofit continua aparecendo em vagas Android porque resolve um problema central: transformar contratos HTTP em interfaces Kotlin testáveis. Em projetos reais, porém, não basta criar uma interface e chamar \u003ccode\u003eapi.buscarDados()\u003c/code\u003e. O app precisa lidar com timeout, token expirado, resposta vazia, erro 401, retry, paginação, logs sem dados sensíveis e sincronização com \u003ca href=\"/tutoriais/kotlin-room-database-tutorial/\"\u003eRoom\u003c/a\u003e ou \u003ca href=\"/tutoriais/datastore-preferences-kotlin/\"\u003eDataStore\u003c/a\u003e. Este guia atualiza o tutorial para essa realidade.\u003c/p\u003e","title":"Retrofit com Kotlin em 2026: Tutorial Android com OkHttp, Coroutines e Cache | Kotlin Brasil"},{"content":"Kotlin Multiplatform Mobile, agora oficialmente chamado apenas de Kotlin Multiplatform (KMP), permite compartilhar lógica de negócio entre Android e iOS usando Kotlin. Diferente de frameworks cross-platform que compartilham também a UI, como Flutter ou React Native, o KMP adota uma abordagem pragmatica: você compartilha o código que faz sentido compartilhar \u0026ndash; lógica de negócio, acesso a dados, validacoes \u0026ndash; e mantém a interface nativa de cada plataforma. Neste guia, vamos configurar um projeto KMP do zero, entender a arquitetura, implementar modulos compartilhados e explorar as melhores práticas para projetos reais.\nPor Que Kotlin Multiplatform A proposta do KMP e diferente de outras solucoes cross-platform. Enquanto Flutter substitui a UI nativa por seu próprio engine de renderizacao e React Native usa uma ponte entre JavaScript e componentes nativos, o KMP compila diretamente para JVM no Android e para código nativo via Kotlin/Native no iOS. Isso significa performance nativa em ambas as plataformas sem camadas de abstração adicionais.\nAs vantagens incluem compartilhamento gradual de código, integração total com projetos existentes é a possibilidade de manter equipes Android e iOS trabalhando com suas ferramentas nativas para a UI.\nConfigurando o Projeto O Kotlin Multiplatform Wizard (disponivel em kmp.jetbrains.com) gera a estrutura inicial. Um projeto KMP tipico possui tres modulos principais:\n// settings.gradle.kts rootProject.name = \u0026#34;MeuAppKMP\u0026#34; include(\u0026#34;:androidApp\u0026#34;) include(\u0026#34;:iosApp\u0026#34;) include(\u0026#34;:shared\u0026#34;) // shared/build.gradle.kts plugins { kotlin(\u0026#34;multiplatform\u0026#34;) id(\u0026#34;com.android.library\u0026#34;) kotlin(\u0026#34;plugin.serialization\u0026#34;) } kotlin { androidTarget { compilations.all { kotlinOptions { jvmTarget = \u0026#34;17\u0026#34; } } } listOf( iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { it.binaries.framework { baseName = \u0026#34;shared\u0026#34; isStatic = true } } sourceSets { val commonMain by getting { dependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2\u0026#34;) implementation(\u0026#34;io.ktor:ktor-client-core:2.3.7\u0026#34;) implementation(\u0026#34;io.ktor:ktor-client-content-negotiation:2.3.7\u0026#34;) implementation(\u0026#34;io.ktor:ktor-serialization-kotlinx-json:2.3.7\u0026#34;) } } val androidMain by getting { dependencies { implementation(\u0026#34;io.ktor:ktor-client-android:2.3.7\u0026#34;) } } val iosMain by getting { dependencies { implementation(\u0026#34;io.ktor:ktor-client-darwin:2.3.7\u0026#34;) } } } } Estrutura de Source Sets O KMP utiliza source sets para organizar código compartilhado e código específico de cada plataforma:\n// shared/src/commonMain/kotlin/ // Código Kotlin puro, compartilhado entre todas as plataformas // shared/src/androidMain/kotlin/ // Código especifico do Android (pode usar APIs do Android SDK) // shared/src/iosMain/kotlin/ // Código especifico do iOS (pode usar APIs do iOS via interop) Expect e Actual O mecanismo expect/actual permite declarar APIs no código comum e implementa-las em cada plataforma:\n// commonMain - Declaracao expect class PlatformInfo() { val nome: String val versao: String } // androidMain - Implementacao Android actual class PlatformInfo actual constructor() { actual val nome: String = \u0026#34;Android\u0026#34; actual val versao: String = \u0026#34;${android.os.Build.VERSION.SDK_INT}\u0026#34; } // iosMain - Implementacao iOS actual class PlatformInfo actual constructor() { actual val nome: String = UIDevice.currentDevice.systemName() actual val versao: String = UIDevice.currentDevice.systemVersion } Outro exemplo prático com armazenamento local:\n// commonMain expect class KeyValueStorage { fun getString(key: String, default: String = \u0026#34;\u0026#34;): String fun putString(key: String, value: String) fun clear() } // androidMain actual class KeyValueStorage(private val context: Context) { private val prefs = context.getSharedPreferences( \u0026#34;app_prefs\u0026#34;, Context.MODE_PRIVATE ) actual fun getString(key: String, default: String): String { return prefs.getString(key, default) ?: default } actual fun putString(key: String, value: String) { prefs.edit().putString(key, value).apply() } actual fun clear() { prefs.edit().clear().apply() } } // iosMain actual class KeyValueStorage { private val defaults = NSUserDefaults.standardUserDefaults actual fun getString(key: String, default: String): String { return defaults.stringForKey(key) ?: default } actual fun putString(key: String, value: String) { defaults.setObject(value, forKey = key) } actual fun clear() { val dicionario = defaults.dictionaryRepresentation() for (key in dicionario.keys) { defaults.removeObjectForKey(key as String) } } } Networking Compartilhado com Ktor O Ktor Client funciona em ambas as plataformas, permitindo compartilhar toda a camada de rede:\n// commonMain class ApiClient { private val httpClient = HttpClient { install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true prettyPrint = true }) } } suspend fun buscarProdutos(): List\u0026lt;ProdutoDto\u0026gt; { return httpClient.get(\u0026#34;https://api.exemplo.com/produtos\u0026#34;) .body() } suspend fun buscarProduto(id: Long): ProdutoDto { return httpClient.get(\u0026#34;https://api.exemplo.com/produtos/$id\u0026#34;) .body() } } @Serializable data class ProdutoDto( val id: Long, val nome: String, val preco: Double, val descricao: String ) Repository Compartilhado O padrão Repository funciona perfeitamente no modulo compartilhado:\n// commonMain class ProdutoRepository( private val apiClient: ApiClient ) { private val _produtos = MutableStateFlow\u0026lt;List\u0026lt;ProdutoDto\u0026gt;\u0026gt;(emptyList()) val produtos: StateFlow\u0026lt;List\u0026lt;ProdutoDto\u0026gt;\u0026gt; = _produtos.asStateFlow() suspend fun carregarProdutos(): Result\u0026lt;List\u0026lt;ProdutoDto\u0026gt;\u0026gt; { return try { val resultado = apiClient.buscarProdutos() _produtos.value = resultado Result.success(resultado) } catch (e: Exception) { Result.failure(e) } } } Integração com o App Android No Android, o modulo shared e consumido como uma dependência normal:\n// androidApp/build.gradle.kts dependencies { implementation(project(\u0026#34;:shared\u0026#34;)) } // Uso no Android class ProdutoViewModel( private val repository: ProdutoRepository ) : ViewModel() { val produtos = repository.produtos .stateIn(viewModelScope, SharingStarted.Lazily, emptyList()) } Integração com o App iOS No iOS, o framework gerado e importado no Swift:\n// No Xcode / Swift import shared class ProdutoViewModel: ObservableObject { @Published var produtos: [ProdutoDto] = [] private let repository = ProdutoRepository( apiClient: ApiClient() ) func carregarProdutos() { Task { let resultado = try await repository.carregarProdutos() // Atualizar estado } } } Boas Práticas com Kotlin Multiplatform Compartilhe lógica, não UI: mantenha a interface nativa para melhor experiência do usuário em cada plataforma. Use interfaces no código comum: defina contratos com interfaces e implemente com expect/actual apenas quando necessário. Prefira bibliotecas multiplatform: Ktor, kotlinx-serialization, SQLDelight e Koin possuem suporte KMP nativo. Teste no commonTest: escreva testes unitarios no source set compartilhado para maxima cobertura entre plataformas. Adoção incremental: comece compartilhando uma camada pequena (modelos de dados, por exemplo) e expanda gradualmente. Mantenha o modulo shared leve: evite dependências pesadas que aumentem o tamanho do framework iOS. Erros Comuns e Armadilhas Congelar objetos no Kotlin/Native: versões mais antigas exigiam que objetos compartilhados entre threads fossem \u0026ldquo;frozen\u0026rdquo;. A partir do novo gerenciador de memória, isso não e mais necessário, mas bibliotecas antigas podem ainda ter essa restricao. Coroutines no iOS: o Swift não entende suspend nativamente. Use wrappers como SKIE ou KMP-NativeCoroutines para expor funções suspensas como Swift async/await. Build times longos: projetos KMP podem ter builds mais demorados. Configure caching adequado e builds incrementais. Ignorar diferencias de plataforma: nem toda funcionalidade pode ou deve ser compartilhada. Permissoes, notificacoes push e acesso a sensores geralmente são melhor tratados nativamente. Dependências transitivas: bibliotecas Java puras não funcionam no iOS. Certifique-se de que todas as dependências do commonMain sejam multiplatform. Conclusão e Próximos Passos O Kotlin Multiplatform oferece uma abordagem equilibrada para o desenvolvimento multiplataforma, combinando compartilhamento de código com interfaces nativas. A tecnologia amadureceu significativamente e já e usada em producao por empresas como Netflix, Philips e Cash App. Para aprofundar seus conhecimentos, explore o Compose Multiplatform para compartilhar também a UI, estude SQLDelight para persistencia multiplatform e consulte os demais guias sobre arquitetura e testes aqui no Kotlin Brasil. Se multiplataforma é seu foco, vale conhecer também Python para scripts e automação cross-platform e Rust para módulos nativos de alta performance.\n","permalink":"https://kotlin.dev.br/guias/guia-kotlin-multiplatform-mobile/","summary":"\u003cp\u003eKotlin Multiplatform Mobile, agora oficialmente chamado apenas de Kotlin Multiplatform (KMP), permite compartilhar lógica de negócio entre Android e iOS usando Kotlin. Diferente de frameworks cross-platform que compartilham também a UI, como Flutter ou React Native, o KMP adota uma abordagem pragmatica: você compartilha o código que faz sentido compartilhar \u0026ndash; lógica de negócio, acesso a dados, validacoes \u0026ndash; e mantém a interface nativa de cada plataforma. Neste guia, vamos configurar um projeto KMP do zero, entender a arquitetura, implementar modulos compartilhados e explorar as melhores práticas para projetos reais.\u003c/p\u003e","title":"Kotlin Multiplatform Mobile (KMM): Guia Completo em Português | Kotlin Brasil"},{"content":"Migrar um projeto de Java para Kotlin é uma decisão estratégica que pode trazer benefícios significativos em termos de produtividade, segurança e manutenibilidade do código. No entanto, essa migração deve ser planejada e executada com cuidado para evitar problemas e garantir que a equipe acompanhe o processo. Neste guia, apresentamos uma abordagem passo a passo para realizar essa transição de forma segura e eficiente.\nPlanejamento da Migração Antes de converter qualquer arquivo, é fundamental estabelecer um plano claro. A migração de Java para Kotlin não precisa ser feita de uma vez — na verdade, a abordagem gradual é fortemente recomendada pela própria JetBrains e pelo Google.\nAvaliação do Projeto Atual Comece avaliando o estado atual do seu projeto:\nTamanho do codebase: quantos arquivos Java existem e qual o nível de complexidade? Cobertura de testes: testes automatizados são essenciais para garantir que a migração não introduza bugs Dependências: verifique se todas as bibliotecas utilizadas são compatíveis com Kotlin Equipe: quantos desenvolvedores precisam ser treinados em Kotlin? Uma boa prática é categorizar os arquivos por complexidade e prioridade. Arquivos simples como POJOs, utilitários e testes são candidatos ideais para começar. Modelos de domínio complexos e classes com lógica de negócio crítica devem ser migrados por último, quando a equipe já estiver confortável com a linguagem.\nDefinindo a Estratégia Existem três estratégias principais para migração:\nEstratégia Descrição Prós Contras Big Bang Migrar tudo de uma vez Resultado rápido Alto risco, muito esforço Gradual Migrar arquivo por arquivo Baixo risco, aprendizado contínuo Processo mais longo Novos em Kotlin Apenas código novo em Kotlin Sem risco de regressão Codebase misto por muito tempo A recomendação para a maioria dos projetos é combinar as estratégias gradual e novos em Kotlin. Todo código novo é escrito em Kotlin, e arquivos Java existentes são migrados progressivamente conforme são modificados. Para uma introdução às diferenças entre as linguagens, consulte nosso guia de Kotlin para desenvolvedores Java.\nConfigurando o Projeto para Kotlin O primeiro passo técnico é adicionar o suporte a Kotlin no seu projeto. Para projetos que usam Gradle, as alterações são simples.\nConfiguração do Gradle com Kotlin DSL // build.gradle.kts plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.0.0\u0026#34; kotlin(\u0026#34;plugin.spring\u0026#34;) version \u0026#34;2.0.0\u0026#34; // se usar Spring kotlin(\u0026#34;plugin.jpa\u0026#34;) version \u0026#34;2.0.0\u0026#34; // se usar JPA } dependencies { implementation(\u0026#34;org.jetbrains.kotlin:kotlin-stdlib\u0026#34;) implementation(\u0026#34;org.jetbrains.kotlin:kotlin-reflect\u0026#34;) // Testes testImplementation(\u0026#34;org.jetbrains.kotlin:kotlin-test\u0026#34;) } kotlin { jvmToolchain(17) } Configuração do Maven // pom.xml - adicione o plugin Kotlin // \u0026lt;plugin\u0026gt; // \u0026lt;groupId\u0026gt;org.jetbrains.kotlin\u0026lt;/groupId\u0026gt; // \u0026lt;artifactId\u0026gt;kotlin-maven-plugin\u0026lt;/artifactId\u0026gt; // \u0026lt;version\u0026gt;2.0.0\u0026lt;/version\u0026gt; // \u0026lt;/plugin\u0026gt; Após configurar o build system, certifique-se de que o projeto compila corretamente antes de iniciar qualquer conversão. Um projeto que já não compila em Java será muito mais difícil de migrar para Kotlin.\nProcesso de Conversão Passo a Passo Com o projeto configurado e compilando, é hora de iniciar a conversão propriamente dita. Siga este processo para cada arquivo:\nPasso 1: Conversão Automática O IntelliJ IDEA oferece uma ferramenta de conversão automática de Java para Kotlin. Para usá-la, abra o arquivo Java e pressione Ctrl+Alt+Shift+K (ou vá em Code \u0026gt; Convert Java File to Kotlin File). A ferramenta faz um bom trabalho na conversão inicial, mas o resultado geralmente precisa de refinamento.\nPasso 2: Refinamento Manual Após a conversão automática, revise o código e aplique padrões idiomáticos de Kotlin:\n// Resultado da conversao automática (nao idiomático) class UsuarioService { fun buscarPorId(id: Long): Usuario? { val usuario: Usuario? = repositorio.findById(id).orElse(null) if (usuario != null) { return usuario } else { throw UsuarioNaoEncontradoException(\u0026#34;Usuário $id nao encontrado\u0026#34;) } } } // Versão idiomática em Kotlin class UsuarioService(private val repositorio: UsuarioRepository) { fun buscarPorId(id: Long): Usuario = repositorio.findById(id).orElseThrow { UsuarioNaoEncontradoException(\u0026#34;Usuário $id nao encontrado\u0026#34;) } } Passo 3: Converter POJOs para Data Classes Uma das conversões mais impactantes é transformar POJOs Java em data classes Kotlin:\n// Antes: classe Java com getters, setters, equals, hashCode, toString // Depois: data class Kotlin data class Produto( val id: Long, val nome: String, val descricao: String?, val preco: Double, val ativo: Boolean = true ) Observe como parâmetros nullable são marcados com ? e valores padrão são definidos diretamente na declaração. Isso elimina a necessidade de builders e construtores telescópicos que são comuns em Java.\nPasso 4: Executar Testes Após cada conversão, execute toda a suíte de testes para garantir que nada foi quebrado. Essa é a razão pela qual uma boa cobertura de testes é pré-requisito para uma migração segura. Consulte nosso guia de testes Android com Kotlin para estratégias de teste eficientes.\nTratando Interoperabilidade Java-Kotlin Durante a migração, seu projeto terá uma mistura de arquivos Java e Kotlin. A interoperabilidade é excelente, mas existem alguns pontos de atenção.\nAnotações de Interoperabilidade Kotlin oferece anotações específicas para melhorar a interação com código Java:\nclass UtilsKotlin { companion object { @JvmStatic fun formatar(texto: String): String = texto.trim().lowercase() @JvmField val VERSAO = \u0026#34;2.0\u0026#34; } // Gera overloads Java para parâmetros com valor padrao @JvmOverloads fun configurar( nome: String, timeout: Int = 30, retry: Boolean = true ) { // implementacao } } Lidando com Nullability do Código Java Quando código Kotlin chama código Java, os tipos retornados são tratados como \u0026ldquo;platform types\u0026rdquo; (tipos de plataforma), representados por um ! no compilador. Isso significa que Kotlin não sabe se o valor pode ser null ou não:\n// Código Java retorna String (platform type: String!) val resultado = javaService.buscarNome() // Boa pratica: declare explicitamente a nullability esperada val resultadoSeguro: String? = javaService.buscarNome() // Ou use operador non-null assertion se tiver certeza val resultadoCerto: String = javaService.buscarNome()!! Recomendamos adicionar anotações @Nullable e @NotNull ao código Java que ainda não foi migrado para facilitar a interoperação. Consulte o glossário para mais detalhes sobre platform types.\nPadrões Comuns de Migração Alguns padrões de código Java possuem equivalentes idiomáticos em Kotlin que vale a pena conhecer.\nSingleton Pattern // Java: classe com construtor privado e instância estática // Kotlin: object declaration object DatabaseConfig { val url = \u0026#34;jdbc:postgresql://localhost:5432/db\u0026#34; val driver = \u0026#34;org.postgresql.Driver\u0026#34; fun conexao(): Connection { return DriverManager.getConnection(url) } } Builder Pattern // Em Kotlin, builders podem ser substituídos por parâmetros nomeados e padrao data class HttpRequest( val url: String, val method: String = \u0026#34;GET\u0026#34;, val headers: Map\u0026lt;String, String\u0026gt; = emptyMap(), val body: String? = null, val timeout: Int = 30000 ) // Uso com argumentos nomeados val request = HttpRequest( url = \u0026#34;https://api.exemplo.com/usuarios\u0026#34;, method = \u0026#34;POST\u0026#34;, body = \u0026#34;\u0026#34;\u0026#34;{\u0026#34;nome\u0026#34;: \u0026#34;Maria\u0026#34;}\u0026#34;\u0026#34;\u0026#34;, timeout = 5000 ) Streams API para Kotlin Collections // Java Streams // list.stream().filter(x -\u0026gt; x \u0026gt; 10).map(x -\u0026gt; x * 2).collect(Collectors.toList()) // Kotlin (mais conciso e nao precisa de .stream() nem .collect()) val resultado = list.filter { it \u0026gt; 10 }.map { it * 2 } Ferramentas e Automação Além da conversão automática da IDE, existem ferramentas que auxiliam no processo de migração:\nDetekt: análise estática para Kotlin, equivalente ao Checkstyle/PMD em Java ktlint: formatador de código Kotlin que garante consistência Gradle Kotlin DSL: migre seus scripts de build de Groovy para Kotlin DSL kotlinx.serialization: substitui bibliotecas como Gson e Jackson com serialização nativa de Kotlin Para integrar essas ferramentas no seu pipeline de entrega contínua, confira nosso guia de CI/CD para Kotlin.\nCronograma e Métricas Estabeleça métricas para acompanhar o progresso da migração:\nPercentual de arquivos Kotlin: monitore a proporção de arquivos .kt vs .java Cobertura de testes: garanta que a cobertura não diminua durante a migração Bugs reportados: acompanhe se a migração está introduzindo regressões Velocidade da equipe: meça se a produtividade está aumentando conforme mais código é convertido Um cronograma realista para um projeto de tamanho médio (50-200 arquivos Java) é de três a seis meses para migração completa usando a abordagem gradual. Projetos maiores podem levar mais tempo, mas os benefícios começam a aparecer desde as primeiras conversões.\nConclusão A migração de Java para Kotlin é um investimento que se paga rapidamente em termos de produtividade, segurança e satisfação da equipe de desenvolvimento. A chave do sucesso está em adotar uma abordagem gradual, manter boa cobertura de testes e treinar a equipe adequadamente. Comece pelos arquivos mais simples, estabeleça padrões de código Kotlin desde o início e aproveite a interoperabilidade total para migrar no ritmo que fizer sentido para o seu projeto. Se você também considera outras linguagens modernas, Go oferece simplicidade e alta performance para backend, enquanto Rust garante segurança de memória sem garbage collector. Para mais recursos práticos, explore nossos tutoriais e consulte o glossário de termos Kotlin.\n","permalink":"https://kotlin.dev.br/guias/migracao-java-para-kotlin/","summary":"\u003cp\u003eMigrar um projeto de Java para Kotlin é uma decisão estratégica que pode trazer benefícios significativos em termos de produtividade, segurança e manutenibilidade do código. No entanto, essa migração deve ser planejada e executada com cuidado para evitar problemas e garantir que a equipe acompanhe o processo. Neste guia, apresentamos uma abordagem passo a passo para realizar essa transição de forma segura e eficiente.\u003c/p\u003e\n\u003ch2 id=\"planejamento-da-migração\"\u003ePlanejamento da Migração\u003c/h2\u003e\n\u003cp\u003eAntes de converter qualquer arquivo, é fundamental estabelecer um plano claro. A migração de Java para Kotlin não precisa ser feita de uma vez — na verdade, a abordagem gradual é fortemente recomendada pela própria JetBrains e pelo Google.\u003c/p\u003e","title":"Migração de Java para Kotlin: Guia Passo a Passo Completo | Kotlin Brasil"},{"content":"Neste tutorial completo, você vai aprender a usar o Room Database com Kotlin para persistência de dados no Android. Vamos cobrir desde a configuração inicial com Entity, DAO e Database até tópicos avançados como TypeConverters, migrations do Room em produção, integração com Flow, relacionamentos entre tabelas e testes de DAOs. O Room é a biblioteca oficial do Google para abstração do SQLite e é parte fundamental do Android Jetpack. Para preferências pequenas, como tema, onboarding e filtros simples, complemente com DataStore Preferences em vez de criar tabelas desnecessárias.\nO que é o Room Database? O Room é uma camada de abstração sobre o SQLite qué fácilita o acesso ao banco de dados local no Android. Ele oferece verificação de queries em tempo de compilação, integração nativa com Coroutines e Flow, e elimina grande parte do código boilerplate necessário para trabalhar com SQLite puro.\nA arquitetura do Room se baseia em três componentes principais:\nEntity: representa uma tabela no banco de dados DAO (Data Access Object): contém os métodos para acessar o banco Database: classe abstrata que serve como ponto de entrada principal Passo 1: Configurando as Dependências Adicione as dependências no build.gradle.kts do módulo app:\nplugins { id(\u0026#34;com.google.devtools.ksp\u0026#34;) version \u0026#34;1.9.22-1.0.17\u0026#34; } dependencies { val roomVersion = \u0026#34;2.6.1\u0026#34; implementation(\u0026#34;androidx.room:room-runtime:$roomVersion\u0026#34;) implementation(\u0026#34;androidx.room:room-ktx:$roomVersion\u0026#34;) // suporte a coroutines ksp(\u0026#34;androidx.room:room-compiler:$roomVersion\u0026#34;) // Para testes testImplementation(\u0026#34;androidx.room:room-testing:$roomVersion\u0026#34;) } Note que usamos KSP (Kotlin Symbol Processing) em vez de KAPT para o processamento de anotações, pois o KSP é significativamente mais rápido.\nPasso 2: Criando a Entity A Entity é uma data class anotada que representa uma tabela no banco:\nimport androidx.room.Entity import androidx.room.PrimaryKey import androidx.room.ColumnInfo @Entity(tableName = \u0026#34;tarefas\u0026#34;) data class Tarefa( @PrimaryKey(autoGenerate = true) val id: Long = 0, @ColumnInfo(name = \u0026#34;titulo\u0026#34;) val titulo: String, @ColumnInfo(name = \u0026#34;descricao\u0026#34;) val descricao: String = \u0026#34;\u0026#34;, @ColumnInfo(name = \u0026#34;concluida\u0026#34;) val concluida: Boolean = false, @ColumnInfo(name = \u0026#34;data_criacao\u0026#34;) val dataCriacao: Long = System.currentTimeMillis(), @ColumnInfo(name = \u0026#34;prioridade\u0026#34;) val prioridade: Int = 0 ) A anotação @Entity define a tabela, @PrimaryKey marca a chave primária e @ColumnInfo permite customizar o nome da coluna. Se o nome da propriedade e da coluna forem iguais, @ColumnInfo é opcional.\nPasso 3: Criando o DAO O DAO define os métodos de acesso ao banco. O Room gera automaticamente a implementação em tempo de compilação:\nimport androidx.room.* import kotlinx.coroutines.flow.Flow @Dao interface TarefaDao { // Retorna Flow para observar mudanças em tempo real @Query(\u0026#34;SELECT * FROM tarefas ORDER BY prioridade DESC, data_criacao DESC\u0026#34;) fun observarTodas(): Flow\u0026lt;List\u0026lt;Tarefa\u0026gt;\u0026gt; // Query com parâmetro @Query(\u0026#34;SELECT * FROM tarefas WHERE id = :id\u0026#34;) suspend fun buscarPorId(id: Long): Tarefa? // Filtro por status @Query(\u0026#34;SELECT * FROM tarefas WHERE concluida = :concluida\u0026#34;) fun observarPorStatus(concluida: Boolean): Flow\u0026lt;List\u0026lt;Tarefa\u0026gt;\u0026gt; // Busca por texto @Query(\u0026#34;SELECT * FROM tarefas WHERE titulo LIKE \u0026#39;%\u0026#39; || :termo || \u0026#39;%\u0026#39;\u0026#34;) suspend fun buscarPorTitulo(termo: String): List\u0026lt;Tarefa\u0026gt; // Inserção — retorna o ID gerado @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun inserir(tarefa: Tarefa): Long // Inserção em lote @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun inserirTodas(tarefas: List\u0026lt;Tarefa\u0026gt;) // Atualização @Update suspend fun atualizar(tarefa: Tarefa) // Deleção @Delete suspend fun deletar(tarefa: Tarefa) // Deleção por query @Query(\u0026#34;DELETE FROM tarefas WHERE concluida = 1\u0026#34;) suspend fun deletarConcluidas(): Int // retorna quantidade removida // Contagem @Query(\u0026#34;SELECT COUNT(*) FROM tarefas WHERE concluida = 0\u0026#34;) fun contarPendentes(): Flow\u0026lt;Int\u0026gt; } Note que métodos que retornam Flow não precisam ser suspend — o Flow já é assíncrono por natureza. Métodos que fazem operações únicas (inserir, atualizar, deletar) devem ser marcados como suspend.\nPasso 4: Criando a Classe Database A classe Database é o ponto de entrada para o Room:\nimport android.content.Context import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase @Database( entities = [Tarefa::class], version = 1, exportSchema = true ) abstract class AppDatabase : RoomDatabase() { abstract fun tarefaDao(): TarefaDao companion object { @Volatile private var INSTANCE: AppDatabase? = null fun getInstance(context: Context): AppDatabase { return INSTANCE ?: synchronized(this) { val instance = Room.databaseBuilder( context.applicationContext, AppDatabase::class.java, \u0026#34;app_database\u0026#34; ).build() INSTANCE = instance instance } } } } O padrão Singleton garante que apenas uma instância do banco exista durante o ciclo de vida do app. O @Volatile assegura que a variável seja visível em todas as threads.\nPasso 5: TypeConverters para Tipos Complexos O Room só suporta tipos primitivos e String nativamente. Para tipos complexos como Date, List ou enums, usamos TypeConverters:\nimport androidx.room.TypeConverter import java.util.Date class Converters { @TypeConverter fun fromTimestamp(value: Long?): Date? { return value?.let { Date(it) } } @TypeConverter fun dateToTimestamp(date: Date?): Long? { return date?.time } @TypeConverter fun fromStringList(value: String?): List\u0026lt;String\u0026gt; { return value?.split(\u0026#34;,\u0026#34;)?.map { it.trim() } ?: emptyList() } @TypeConverter fun stringListToString(list: List\u0026lt;String\u0026gt;): String { return list.joinToString(\u0026#34;,\u0026#34;) } } Registre os converters na classe Database:\n@Database(entities = [Tarefa::class], version = 1) @TypeConverters(Converters::class) abstract class AppDatabase : RoomDatabase() { abstract fun tarefaDao(): TarefaDao // ... } Passo 6: Migrations — Evoluindo o Esquema do Banco Quando você precisa alterar a estrutura do banco (adicionar coluna, criar tabela), é necessário criar uma migration para não perder os dados dos usuários:\nimport androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase val MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL(\u0026#34;ALTER TABLE tarefas ADD COLUMN categoria TEXT NOT NULL DEFAULT \u0026#39;\u0026#39;\u0026#34;) } } val MIGRATION_2_3 = object : Migration(2, 3) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL(\u0026#34;\u0026#34;\u0026#34; CREATE TABLE IF NOT EXISTS categorias ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, nome TEXT NOT NULL, cor TEXT NOT NULL DEFAULT \u0026#39;#000000\u0026#39; ) \u0026#34;\u0026#34;\u0026#34;.trimIndent()) } } // Aplique as migrations ao criar o banco: Room.databaseBuilder(context, AppDatabase::class.java, \u0026#34;app_database\u0026#34;) .addMigrations(MIGRATION_1_2, MIGRATION_2_3) .build() Passo 7: Relacionamentos entre Tabelas O Room suporta relacionamentos 1:1, 1:N e N:N através de anotações como @Embedded e @Relation:\nRelacionamento 1:N (um usuário tem muitas tarefas):\n@Entity(tableName = \u0026#34;usuarios\u0026#34;) data class Usuario( @PrimaryKey(autoGenerate = true) val id: Long = 0, val nome: String ) @Entity( tableName = \u0026#34;tarefas\u0026#34;, foreignKeys = [ForeignKey( entity = Usuario::class, parentColumns = [\u0026#34;id\u0026#34;], childColumns = [\u0026#34;usuario_id\u0026#34;], onDelete = ForeignKey.CASCADE )] ) data class Tarefa( @PrimaryKey(autoGenerate = true) val id: Long = 0, val titulo: String, @ColumnInfo(name = \u0026#34;usuario_id\u0026#34;) val usuarioId: Long ) // Classe intermediária para o resultado da consulta data class UsuarioComTarefas( @Embedded val usuario: Usuario, @Relation( parentColumn = \u0026#34;id\u0026#34;, entityColumn = \u0026#34;usuario_id\u0026#34; ) val tarefas: List\u0026lt;Tarefa\u0026gt; ) // No DAO: @Transaction @Query(\u0026#34;SELECT * FROM usuarios WHERE id = :id\u0026#34;) suspend fun buscarUsuarioComTarefas(id: Long): UsuarioComTarefas? Relacionamento N:N (tarefas com múltiplas tags):\n@Entity(tableName = \u0026#34;tags\u0026#34;) data class Tag( @PrimaryKey(autoGenerate = true) val id: Long = 0, val nome: String ) @Entity( tableName = \u0026#34;tarefa_tag\u0026#34;, primaryKeys = [\u0026#34;tarefaId\u0026#34;, \u0026#34;tagId\u0026#34;] ) data class TarefaTagCrossRef( val tarefaId: Long, val tagId: Long ) data class TarefaComTags( @Embedded val tarefa: Tarefa, @Relation( parentColumn = \u0026#34;id\u0026#34;, entityColumn = \u0026#34;id\u0026#34;, associateBy = Junction( value = TarefaTagCrossRef::class, parentColumn = \u0026#34;tarefaId\u0026#34;, entityColumn = \u0026#34;tagId\u0026#34; ) ) val tags: List\u0026lt;Tag\u0026gt; ) Passo 8: Integração com Flow para Dados Reativos A integração com Flow permite que a UI seja atualizada automaticamente quando os dados mudam:\nclass TarefaRepository(private val dao: TarefaDao) { val todasTarefas: Flow\u0026lt;List\u0026lt;Tarefa\u0026gt;\u0026gt; = dao.observarTodas() val pendentes: Flow\u0026lt;Int\u0026gt; = dao.contarPendentes() suspend fun adicionar(tarefa: Tarefa) = dao.inserir(tarefa) suspend fun concluir(tarefa: Tarefa) = dao.atualizar(tarefa.copy(concluida = true)) suspend fun remover(tarefa: Tarefa) = dao.deletar(tarefa) } // No ViewModel: class TarefaViewModel(private val repository: TarefaRepository) : ViewModel() { val tarefas: StateFlow\u0026lt;List\u0026lt;Tarefa\u0026gt;\u0026gt; = repository.todasTarefas .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) fun adicionarTarefa(titulo: String) { viewModelScope.launch { repository.adicionar(Tarefa(titulo = titulo)) } } } Passo 9: Testando os DAOs O Room fornece ferramentas para testes usando banco de dados em memória:\nimport androidx.room.Room import androidx.test.core.app.ApplicationProvider import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Before import org.junit.Test import org.junit.Assert.* class TarefaDaoTest { private lateinit var database: AppDatabase private lateinit var dao: TarefaDao @Before fun setup() { database = Room.inMemoryDatabaseBuilder( ApplicationProvider.getApplicationContext(), AppDatabase::class.java ).allowMainThreadQueries().build() dao = database.tarefaDao() } @After fun tearDown() { database.close() } @Test fun inserirEBuscarTarefa() = runTest { val tarefa = Tarefa(titulo = \u0026#34;Estudar Room\u0026#34;, descricao = \u0026#34;Tutorial completo\u0026#34;) val id = dao.inserir(tarefa) val resultado = dao.buscarPorId(id) assertNotNull(resultado) assertEquals(\u0026#34;Estudar Room\u0026#34;, resultado?.titulo) } @Test fun observarTarefasRetornaFlowAtualizado() = runTest { dao.inserir(Tarefa(titulo = \u0026#34;Tarefa 1\u0026#34;)) dao.inserir(Tarefa(titulo = \u0026#34;Tarefa 2\u0026#34;)) val tarefas = dao.observarTodas().first() assertEquals(2, tarefas.size) } @Test fun deletarConcluidas() = runTest { dao.inserir(Tarefa(titulo = \u0026#34;Pendente\u0026#34;, concluida = false)) dao.inserir(Tarefa(titulo = \u0026#34;Feita\u0026#34;, concluida = true)) val removidas = dao.deletarConcluidas() assertEquals(1, removidas) val restantes = dao.observarTodas().first() assertEquals(1, restantes.size) assertEquals(\u0026#34;Pendente\u0026#34;, restantes[0].titulo) } } Erros Comuns Acessar o banco na main thread: O Room bloqueia operações na thread principal por padrão. Use coroutines (funções suspend) ou Flow para acesso assíncrono. Nunca use allowMainThreadQueries() em produção.\nEsquecer @Transaction em queries com relacionamentos: Consultas que retornam objetos com @Relation devem ser anotadas com @Transaction para garantir consistência dos dados.\nNão criar migrations ao alterar o esquema: Se você mudar a versão do banco sem fornecer uma migration, o app vai crashar. Use fallbackToDestructiveMigration() apenas durante o desenvolvimento.\nPassar a mesma instância de lista ao Flow: O Room já cuida da reatividade. Não tente contornar o sistema criando seus próprios mecanismos de notificação.\nIgnorar exportSchema = true: Habilitar a exportação do schema permite que o Room gere arquivos JSON que são essenciais para validar migrations automaticamente nos testes.\nConclusão e Próximos Passos Neste tutorial, você aprendeu a utilizar o Room Database com Kotlin de forma completa: desde a criação de Entities, DAOs e a classe Database, passando por TypeConverters, migrations para evolução do schema, relacionamentos 1:1, 1:N e N:N, integração reativa com Flow, até testes automatizados dos DAOs.\nComo próximos passos, recomendamos:\nIntegrar o Room com a arquitetura MVVM para uma separação de responsabilidades clara Combinar Room com Retrofit para sincronizar dados locais e remotos Explorar o Kotlin Flow para técnicas avançadas de observação de dados Consultar o glossário de coroutine e data class para reforçar os conceitos utilizados O Room é uma peça essencial em qualquer app Android moderno e dominá-lo vai melhorar significativamente a qualidade dos seus projetos.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-room-database-tutorial/","summary":"\u003cp\u003eNeste tutorial completo, você vai aprender a usar o \u003cstrong\u003eRoom Database\u003c/strong\u003e com Kotlin para persistência de dados no Android. Vamos cobrir desde a configuração inicial com Entity, DAO e Database até tópicos avançados como TypeConverters, \u003ca href=\"/blog/migrations-room-android-kotlin-2026/\"\u003emigrations do Room em produção\u003c/a\u003e, integração com \u003ca href=\"/glossario/flow/\"\u003eFlow\u003c/a\u003e, relacionamentos entre tabelas e testes de DAOs. O Room é a biblioteca oficial do Google para abstração do SQLite e é parte fundamental do Android Jetpack. Para preferências pequenas, como tema, onboarding e filtros simples, complemente com \u003ca href=\"/tutoriais/datastore-preferences-kotlin/\"\u003eDataStore Preferences\u003c/a\u003e em vez de criar tabelas desnecessárias.\u003c/p\u003e","title":"Room Database com Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Kotlin Coroutines transformaram a forma como lidamos com programação assíncrona e concorrente na JVM. Antes das coroutines, desenvolvedores precisavam lidar com callbacks aninhados, RxJava complexo ou threads manuais para executar operações assíncronas. As coroutines oferecem uma abordagem sequencial para código assíncrono, onde funções suspensas podem ser pausadas e retomadas sem bloquear threads. Este guia cobre desde os fundamentos até padrões avançados que você vai usar em projetos reais, tanto no Android quanto no backend.\nO Que São Coroutines Uma coroutine é uma instancia de computacao suspensavel. Diferente de threads, que são gerenciadas pelo sistema operacional e consomem recursos significativos, coroutines são leves e gerenciadas pelo runtime do Kotlin. Você pode lancar milhares de coroutines sem impacto significativo no consumo de memória, algo impraticavel com threads tradicionais.\nimport kotlinx.coroutines.* fun main() = runBlocking { launch { delay(1000L) println(\u0026#34;Mundo!\u0026#34;) } println(\u0026#34;Ola,\u0026#34;) } // Saida: // Ola, // Mundo! O runBlocking cria um escopo de coroutine que bloqueia a thread atual até que todas as coroutines filhas terminem. O launch inicia uma nova coroutine sem bloquear, e delay e uma função suspensa que pausa a coroutine sem bloquear a thread.\nSuspend Functions Funções marcadas com suspend podem ser pausadas e retomadas. Elas só podem ser chamadas de dentro de outras funções suspensas ou de um escopo de coroutine:\nsuspend fun buscarUsuario(id: Long): Usuario { return withContext(Dispatchers.IO) { // Simula chamada de rede val resposta = apiService.buscarUsuario(id) resposta.toDomain() } } suspend fun buscarPedidos(usuarioId: Long): List\u0026lt;Pedido\u0026gt; { return withContext(Dispatchers.IO) { apiService.buscarPedidos(usuarioId).map { it.toDomain() } } } // Chamadas sequenciais suspend fun carregarDashboard(usuarioId: Long): Dashboard { val usuario = buscarUsuario(usuarioId) val pedidos = buscarPedidos(usuarioId) return Dashboard(usuario, pedidos) } // Chamadas paralelas com async suspend fun carregarDashboardParalelo(usuarioId: Long): Dashboard { return coroutineScope { val usuarioDeferred = async { buscarUsuario(usuarioId) } val pedidosDeferred = async { buscarPedidos(usuarioId) } Dashboard(usuarioDeferred.await(), pedidosDeferred.await()) } } A versão paralela com async e await executa ambas as chamadas simultaneamente, reduzindo o tempo total de espera.\nDispatchers Os Dispatchers determinam em qual thread ou pool de threads a coroutine sera executada:\n// Dispatchers.Main - Thread principal (UI no Android) // Dispatchers.IO - Pool otimizado para I/O (rede, disco) // Dispatchers.Default - Pool otimizado para CPU (calculos) // Dispatchers.Unconfined - Sem thread especifica suspend fun exemploDispatchers() { // Operação de rede val dados = withContext(Dispatchers.IO) { apiService.buscarDados() } // Processamento pesado val resultado = withContext(Dispatchers.Default) { dados.map { item -\u0026gt; processarItem(item) // CPU intensivo } } // Atualizar UI (Android) withContext(Dispatchers.Main) { exibirResultado(resultado) } } O withContext troca o dispatcher dentro de uma função suspensa, permitindo executar cada operação no contexto mais adequado.\nEscopos de Coroutine Cada coroutine pertence a um escopo que gerencia seu ciclo de vida. No Android, os escopos mais comuns são viewModelScope e lifecycleScope:\nclass MinhaViewModel : ViewModel() { fun carregarDados() { // Cancelado automaticamente quando o ViewModel e destruido viewModelScope.launch { try { val resultado = repository.buscarDados() _estado.value = Estado.Sucesso(resultado) } catch (e: CancellationException) { throw e // Nunca engula CancellationException } catch (e: Exception) { _estado.value = Estado.Erro(e.message) } } } } // Escopo personalizado class MeuServico { private val scope = CoroutineScope( SupervisorJob() + Dispatchers.Default ) fun iniciar() { scope.launch { // Trabalho em background } } fun encerrar() { scope.cancel() // Cancela todas as coroutines } } Structured Concurrency Structured concurrency garante que coroutines filhas sejam canceladas quando o escopo pai e cancelado, evitando leaks de coroutines:\nsuspend fun processarLote(itens: List\u0026lt;Item\u0026gt;) = coroutineScope { val resultados = itens.map { item -\u0026gt; async { processarItem(item) } } // Se qualquer async falhar, todas são canceladas resultados.awaitAll() } // Com SupervisorScope, falhas nao propagam para irmaos suspend fun processarLoteIndependente(itens: List\u0026lt;Item\u0026gt;) = supervisorScope { val resultados = itens.map { item -\u0026gt; async { try { processarItem(item) } catch (e: Exception) { null // Falha individual nao cancela as demais } } } resultados.awaitAll().filterNotNull() } Kotlin Flow Flow e a API para streams reativos das coroutines. Diferente do suspend, que retorna um único valor, Flow emite múltiplos valores ao longo do tempo:\n// Criando um Flow fun contadorFlow(): Flow\u0026lt;Int\u0026gt; = flow { var contador = 0 while (true) { emit(contador++) delay(1000L) } } // Operadores de transformacao fun buscarProdutosFlow(query: String): Flow\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt; { return flowOf(query) .debounce(300L) .filter { it.length \u0026gt;= 3 } .flatMapLatest { consulta -\u0026gt; repository.buscarProdutos(consulta) } .catch { e -\u0026gt; emit(emptyList()) } .flowOn(Dispatchers.IO) } // Coletando um Flow viewModelScope.launch { buscarProdutosFlow(\u0026#34;kotlin\u0026#34;) .collect { produtos -\u0026gt; _estado.value = Estado.Sucesso(produtos) } } StateFlow e SharedFlow StateFlow e SharedFlow são versões especializadas de Flow para compartilhar estado e eventos:\nclass ConfigViewModel : ViewModel() { // StateFlow - sempre tem um valor atual private val _tema = MutableStateFlow(Tema.CLARO) val tema: StateFlow\u0026lt;Tema\u0026gt; = _tema.asStateFlow() // SharedFlow - para eventos que nao precisam de valor inicial private val _notificacoes = MutableSharedFlow\u0026lt;String\u0026gt;() val notificacoes: SharedFlow\u0026lt;String\u0026gt; = _notificacoes.asSharedFlow() fun alternarTema() { _tema.value = if (_tema.value == Tema.CLARO) Tema.ESCURO else Tema.CLARO } fun enviarNotificacao(mensagem: String) { viewModelScope.launch { _notificacoes.emit(mensagem) } } } Tratamento de Erros O tratamento de erros em coroutines exige atencao especial:\n// CoroutineExceptionHandler para erros nao tratados val handler = CoroutineExceptionHandler { _, exception -\u0026gt; println(\u0026#34;Erro capturado: ${exception.message}\u0026#34;) } val scope = CoroutineScope(SupervisorJob() + handler) // Try-catch em funcoes suspensas suspend fun operacaoSegura(): Result\u0026lt;Dados\u0026gt; { return try { val dados = apiService.buscarDados() Result.success(dados) } catch (e: CancellationException) { throw e // NUNCA capture CancellationException } catch (e: HttpException) { Result.failure(e) } catch (e: IOException) { Result.failure(e) } } // Retry com backoff exponencial suspend fun \u0026lt;T\u0026gt; retryComBackoff( tentativas: Int = 3, delayInicial: Long = 1000L, fator: Double = 2.0, bloco: suspend () -\u0026gt; T ): T { var delayAtual = delayInicial repeat(tentativas - 1) { try { return bloco() } catch (e: Exception) { delay(delayAtual) delayAtual = (delayAtual * fator).toLong() } } return bloco() // Ultima tentativa sem catch } Boas Práticas com Coroutines Nunca capture CancellationException: ela e o mecanismo de cancelamento das coroutines. Captura-la impede o cancelamento correto. Use withContext para trocar dispatchers: em vez de criar novos escopos, use withContext dentro de funções suspensas. Prefira coroutineScope a GlobalScope: GlobalScope não respeita structured concurrency e pode causar leaks. Exponha Flow em vez de suspend para streams: se os dados mudam ao longo do tempo, Flow e mais apropriado. Teste com runTest: o kotlinx-coroutines-test fornece runTest para testar coroutines de forma deterministica. Injete dispatchers: passe dispatchers como parametro para facilitar testes. Erros Comuns e Armadilhas Bloquear thread dentro de coroutine: chamar Thread.sleep() em vez de delay() bloqueia a thread da coroutine. Criar coroutines sem escopo adequado: usar GlobalScope.launch e quase sempre um erro. Vincule ao ciclo de vida do componente. Ignorar cancelamento: funções suspensas longas devem verificar isActive periodicamente ou usar funções suspensas cooperativas. Misturar callbacks com coroutines: use suspendCancellableCoroutine para converter callbacks em funções suspensas corretamente. Coleta duplicada de StateFlow: coletar o mesmo StateFlow em múltiplos locais sem necessidade pode causar processamento redundante. Conclusão e Próximos Passos Kotlin Coroutines oferecem uma abordagem poderosa e elegante para programação assíncrona. Com suspend functions, Flow, structured concurrency e dispatchers, você tem todas as ferramentas necessarias para construir aplicações responsivas e eficientes. Domine esses conceitos e aplique-os tanto no desenvolvimento Android quanto no backend com frameworks como Ktor e Spring Boot. Para comparar modelos de concorrência, veja como Go implementa goroutines, channels e pipelines e como Rust aborda async/await em profundidade. Explore os guias complementares sobre testes e arquitetura aqui no Kotlin Brasil para aprofundar ainda mais seu conhecimento.\n","permalink":"https://kotlin.dev.br/guias/guia-coroutines-completo/","summary":"\u003cp\u003eKotlin Coroutines transformaram a forma como lidamos com programação assíncrona e concorrente na JVM. Antes das coroutines, desenvolvedores precisavam lidar com callbacks aninhados, RxJava complexo ou threads manuais para executar operações assíncronas. As coroutines oferecem uma abordagem sequencial para código assíncrono, onde funções suspensas podem ser pausadas e retomadas sem bloquear threads. Este guia cobre desde os fundamentos até padrões avançados que você vai usar em projetos reais, tanto no Android quanto no backend.\u003c/p\u003e","title":"Kotlin Coroutines: Guia Completo em Português | Kotlin Brasil"},{"content":"O Kotlin Multiplatform (KMP) é uma das tecnologias mais promissoras do ecossistema de desenvolvimento moderno. Depois de anos em desenvolvimento e beta, KMP atingiu estabilidade e esta mudando a forma como empresas pensam sobre compartilhamento de código. Neste artigo, vamos explorar onde o KMP esta hoje, para onde esta indo e por que você deveria prestar atencao.\nO Que e KMP e Por Que Importa Kotlin Multiplatform permite que você escreva código Kotlin que compila para múltiplas plataformas: JVM (Android, server), nativo (iOS, macOS, Linux, Windows), JavaScript e WebAssembly. A ideia central não e \u0026ldquo;write once, run anywhere\u0026rdquo; como Java prometia, mas sim \u0026ldquo;write once, adapt where needed\u0026rdquo;.\n// commonMain - Código que roda em TODAS as plataformas interface UserRepository { suspend fun getUser(id: String): User? suspend fun saveUser(user: User) fun observeUsers(): Flow\u0026lt;List\u0026lt;User\u0026gt;\u0026gt; } class UserRepositoryImpl( private val api: UserApi, private val cache: UserCache, private val dispatcher: CoroutineDispatcher ) : UserRepository { override suspend fun getUser(id: String): User? { return withContext(dispatcher) { cache.get(id) ?: api.fetchUser(id)?.also { user -\u0026gt; cache.save(user) } } } override suspend fun saveUser(user: User) { withContext(dispatcher) { api.updateUser(user) cache.save(user) } } override fun observeUsers(): Flow\u0026lt;List\u0026lt;User\u0026gt;\u0026gt; { return cache.observeAll() .onStart { val remote = api.fetchAllUsers() cache.saveAll(remote) } } } Esse código funciona identicamente no Android, iOS, desktop e server. Apenas as implementacoes específicas de plataforma (como acesso a banco de dados ou sistema de arquivos) precisam de adaptacao.\nEstado Atual do KMP Bibliotecas Estáveis O ecossistema de bibliotecas KMP cresceu enormemente:\n// build.gradle.kts - Dependências KMP kotlin { sourceSets { commonMain.dependencies { // Networking implementation(\u0026#34;io.ktor:ktor-client-core:3.0.0\u0026#34;) // Serializacao implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0\u0026#34;) // Coroutines implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0\u0026#34;) // Date/Time implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-datetime:0.6.0\u0026#34;) // Database implementation(\u0026#34;app.cash.sqldelight:runtime:2.1.0\u0026#34;) // DI implementation(\u0026#34;io.insert-koin:koin-core:4.0.0\u0026#34;) } } } Todas essas bibliotecas são maduras, bem mantidas e usadas em producao por empresas globais.\nEmpresas Que Usam KMP A lista de empresas usando KMP em producao e impressionante e continua crescendo:\nNetflix: Compartilha lógica entre Android e iOS Cash App: Pioneira no uso de KMP para mobile Philips: Usa KMP em dispositivos medicos VMware: Compartilha lógica em ferramentas enterprise Touchlab: Consultoria especializada em KMP No Brasil, fintechs e bancos digitais estao adotando KMP para reduzir duplicacao de lógica entre plataformas mobile.\nArquitetura de Projetos KMP Estrutura de Modulos Uma arquitetura KMP bem organizada segue o princípio de separação por feature:\n// Estrutura tipica de projeto KMP // shared/ // commonMain/ -\u0026gt; Código compartilhado // androidMain/ -\u0026gt; Implementacoes Android // iosMain/ -\u0026gt; Implementacoes iOS // jvmMain/ -\u0026gt; Implementacoes JVM (server) // Definicao de plataforma expect class DatabaseDriverFactory { fun createDriver(): SqlDriver } // androidMain actual class DatabaseDriverFactory(private val context: Context) { actual fun createDriver(): SqlDriver { return AndroidSqliteDriver( AppDatabase.Schema, context, \u0026#34;app.db\u0026#34; ) } } // iosMain actual class DatabaseDriverFactory { actual fun createDriver(): SqlDriver { return NativeSqliteDriver( AppDatabase.Schema, \u0026#34;app.db\u0026#34; ) } } ViewModel Compartilhado Uma das evolucoes mais significativas e a possibilidade de compartilhar ViewModels entre plataformas:\n// commonMain - ViewModel compartilhado class ProductListViewModel( private val repository: ProductRepository ) : ViewModel() { private val _uiState = MutableStateFlow(ProductListState()) val uiState: StateFlow\u0026lt;ProductListState\u0026gt; = _uiState.asStateFlow() init { loadProducts() } fun loadProducts() { viewModelScope.launch { _uiState.update { it.copy(loading = true) } repository.getProducts() .onSuccess { products -\u0026gt; _uiState.update { it.copy(loading = false, products = products) } } .onFailure { error -\u0026gt; _uiState.update { it.copy(loading = false, error = error.message) } } } } fun search(query: String) { viewModelScope.launch { val filtered = repository.searchProducts(query) _uiState.update { it.copy(products = filtered) } } } } data class ProductListState( val loading: Boolean = false, val products: List\u0026lt;Product\u0026gt; = emptyList(), val error: String? = null ) O Futuro: Compose Multiplatform O proximo grande passo do KMP e o Compose Multiplatform, que permite compartilhar até a camada de UI:\n// Compose Multiplatform - UI compartilhada entre Android, iOS e desktop @Composable fun ProductListScreen(viewModel: ProductListViewModel) { val state by viewModel.uiState.collectAsState() Scaffold( topBar = { TopAppBar(title = { Text(\u0026#34;Produtos\u0026#34;) }) } ) { padding -\u0026gt; when { state.loading -\u0026gt; { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { CircularProgressIndicator() } } state.error != null -\u0026gt; { ErrorMessage( message = state.error!!, onRetry = { viewModel.loadProducts() } ) } else -\u0026gt; { LazyColumn(contentPadding = padding) { items(state.products) { product -\u0026gt; ProductItem(product) } } } } } } Com Compose Multiplatform, a promessa e: escreva a UI uma vez e rode em Android, iOS, desktop e web. E diferente do Flutter porque usa componentes nativos do Material Design e permite integrar componentes nativos da plataforma quando necessário.\nDesafios e Limitações Atuais Nem tudo são flores. O KMP ainda tem desafios:\nBuild Times Projetos KMP grandes podem ter tempos de build significativos. A JetBrains esta trabalhando em melhorias no compilador K2 que prometem reduzir isso substancialmente.\nDebugging iOS Debugar código Kotlin rodando no iOS ainda não e tao fluido quanto debugar código Swift nativo. Melhorias estao vindo, mas e uma area que precisa de atencao.\nCurva de Aprendizado Para times que não conhecem Kotlin, a curva de aprendizado inclui não apenas a linguagem mas também o sistema de build com Gradle, a configuração de targets e as particularidades de cada plataforma.\nRoadmap e Expectativas A JetBrains tem investido pesadamente no KMP, e as proximas evolucoes incluem:\nCompose Multiplatform para iOS estavel: A interface compartilhada entre todas as plataformas Melhorias no Kotlin/Native: Performance e tooling para targets nativos Kotlin/WASM: Rodar Kotlin no navegador com performance nativa Integração com SwiftUI: Melhor interop com o ecossistema Apple Compilador K2: Compilação mais rápida e recursos novos da linguagem Como Comecar com KMP Se você quer começar com KMP hoje, siga estes passos:\nDomine Kotlin: Certifique-se de que você conhece bem a linguagem Crie um projeto KMP simples: Use o wizard do Android Studio ou o KMP plugin do IntelliJ Comece pela camada de dados: Compartilhe networking e modelos de dados primeiro Expanda gradualmente: Adicione lógica de negocios, ViewModels e eventualmente UI Contribua para o ecossistema: Muitas bibliotecas precisam de suporte KMP // Primeiro projeto KMP - Networking compartilhado // commonMain class ApiClient(private val httpClient: HttpClient) { suspend fun getPosts(): List\u0026lt;Post\u0026gt; { return httpClient.get(\u0026#34;https://api.example.com/posts\u0026#34;).body() } } @Serializable data class Post( val id: Int, val title: String, val body: String, val userId: Int ) Conclusão O futuro do Kotlin Multiplatform e extremamente promissor. A tecnologia saiu do estagio experimental e esta pronta para producao. Com Compose Multiplatform amadurecendo, Kotlin/WASM avancando e o ecossistema de bibliotecas crescendo, KMP esta se posicionando como a plataforma multiplataforma mais completa e robusta do mercado.\nPara desenvolvedores e empresas brasileiras, adotar KMP agora significa estar a frente da curva. No espaço multiplataforma, Rust com WebAssembly é outra tecnologia promissora, especialmente para workloads de alta performance. O investimento em aprendizado hoje se traduz em produtividade e oportunidades amanha. Acompanhe o blog do Kotlin Brasil para ficar por dentro de todas as novidades do ecossistema KMP.\n","permalink":"https://kotlin.dev.br/blog/futuro-kotlin-multiplatform/","summary":"\u003cp\u003eO Kotlin Multiplatform (KMP) é uma das tecnologias mais promissoras do ecossistema de desenvolvimento moderno. Depois de anos em desenvolvimento e beta, KMP atingiu estabilidade e esta mudando a forma como empresas pensam sobre compartilhamento de código. Neste artigo, vamos explorar onde o KMP esta hoje, para onde esta indo e por que você deveria prestar atencao.\u003c/p\u003e\n\u003ch2 id=\"o-que-e-kmp-e-por-que-importa\"\u003eO Que e KMP e Por Que Importa\u003c/h2\u003e\n\u003cp\u003eKotlin Multiplatform permite que você escreva código Kotlin que compila para múltiplas plataformas: JVM (Android, server), nativo (iOS, macOS, Linux, Windows), JavaScript e WebAssembly. A ideia central não e \u0026ldquo;write once, run anywhere\u0026rdquo; como Java prometia, mas sim \u0026ldquo;write once, adapt where needed\u0026rdquo;.\u003c/p\u003e","title":"O Futuro do Kotlin Multiplatform: Guia Completo | Kotlin Brasil"},{"content":"Neste tutorial, você vai aprender a implementar o RecyclerView no Android usando Kotlin, desde a configuração básica até técnicas avançadas como DiffUtil, ListAdapter, múltiplos view types e tratamento de cliques. O RecyclerView é o componente mais importante para exibir listas no Android, e dominá-lo é essencial para qualquer desenvolvedor Android.\nO que é o RecyclerView? O RecyclerView é um componente do AndroidX que exibe grandes conjuntos de dados de forma eficiente, reciclando views que saem da tela para reutilizá-las com novos dados. Ele substitui o antigo ListView e oferece muito mais flexibilidade através de três componentes principais:\nAdapter: responsável por criar e vincular os dados às views ViewHolder: mantém referências às views de cada item, evitando chamadas repetidas a findViewById LayoutManager: define como os itens são posicionados (lista vertical, horizontal, grade, etc.) Passo 1: Configurando o Projeto Primeiro, adicione a dependência do RecyclerView no build.gradle.kts do módulo app:\ndependencies { implementation(\u0026#34;androidx.recyclerview:recyclerview:1.3.2\u0026#34;) } Crie o modelo de dados usando uma data class:\ndata class Contato( val id: Long, val nome: String, val email: String, val fotoUrl: String? = null ) Passo 2: Criando o Layout do Item Crie o arquivo item_contato.xml na pasta res/layout/:\n// Referência do layout XML - item_contato.xml // LinearLayout vertical com: // - TextView para nome (id: tvNome) // - TextView para email (id: tvEmail) // - Padding de 16dp e margin bottom de 8dp Na prática, você criará um XML com os componentes visuais necessários. Aqui focaremos no código Kotlin.\nPasso 3: Implementando o ViewHolder e o Adapter O ViewHolder encapsula a view de cada item, e o Adapter gerencia a criação e vinculação dos dados:\nimport android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.RecyclerView class ContatoAdapter( private var contatos: List\u0026lt;Contato\u0026gt; = emptyList() ) : RecyclerView.Adapter\u0026lt;ContatoAdapter.ContatoViewHolder\u0026gt;() { // ViewHolder mantém referências às views do item class ContatoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val tvNome: TextView = itemView.findViewById(R.id.tvNome) val tvEmail: TextView = itemView.findViewById(R.id.tvEmail) fun bind(contato: Contato) { tvNome.text = contato.nome tvEmail.text = contato.email } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContatoViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_contato, parent, false) return ContatoViewHolder(view) } override fun onBindViewHolder(holder: ContatoViewHolder, position: Int) { holder.bind(contatos[position]) } override fun getItemCount(): Int = contatos.size fun atualizarLista(novosContatos: List\u0026lt;Contato\u0026gt;) { contatos = novosContatos notifyDataSetChanged() // veremos uma alternativa melhor com DiffUtil } } Passo 4: Configurando o RecyclerView na Activity/Fragment Agora conectamos tudo na Activity ou Fragment:\nimport android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView class ContatosActivity : AppCompatActivity() { private lateinit var recyclerView: RecyclerView private lateinit var adapter: ContatoAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_contatos) recyclerView = findViewById(R.id.rvContatos) // LayoutManager define a disposição dos itens recyclerView.layoutManager = LinearLayoutManager(this) // Opcional: melhora performance quando os itens têm tamanho fixo recyclerView.setHasFixedSize(true) adapter = ContatoAdapter() recyclerView.adapter = adapter // Simula carregamento de dados val contatos = listOf( Contato(1, \u0026#34;Ana Silva\u0026#34;, \u0026#34;ana@email.com\u0026#34;), Contato(2, \u0026#34;Bruno Costa\u0026#34;, \u0026#34;bruno@email.com\u0026#34;), Contato(3, \u0026#34;Carla Dias\u0026#34;, \u0026#34;carla@email.com\u0026#34;) ) adapter.atualizarLista(contatos) } } O LayoutManager controla o posicionamento. As opções mais comuns são:\n// Lista vertical (padrao) LinearLayoutManager(context) // Lista horizontal LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) // Grade com 2 colunas GridLayoutManager(context, 2) // Grade escalonada (estilo Pinterest) StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) Passo 5: DiffUtil e ListAdapter — Atualizações Eficientes Usar notifyDataSetChanged() é ineficiente porque recria todas as views. O DiffUtil calcula as diferenças entre duas listas e aplica apenas as mudanças necessárias com animações automáticas. O ListAdapter simplifica esse processo:\nimport androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter class ContatoDiffCallback : DiffUtil.ItemCallback\u0026lt;Contato\u0026gt;() { override fun areItemsTheSame(oldItem: Contato, newItem: Contato): Boolean { return oldItem.id == newItem.id // verifica se e o mesmo item } override fun areContentsTheSame(oldItem: Contato, newItem: Contato): Boolean { return oldItem == newItem // verifica se o conteúdo mudou } } class ContatoListAdapter( private val onItemClick: (Contato) -\u0026gt; Unit ) : ListAdapter\u0026lt;Contato, ContatoListAdapter.ContatoViewHolder\u0026gt;(ContatoDiffCallback()) { inner class ContatoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private val tvNome: TextView = itemView.findViewById(R.id.tvNome) private val tvEmail: TextView = itemView.findViewById(R.id.tvEmail) init { itemView.setOnClickListener { val position = bindingAdapterPosition if (position != RecyclerView.NO_POSITION) { onItemClick(getItem(position)) } } } fun bind(contato: Contato) { tvNome.text = contato.nome tvEmail.text = contato.email } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContatoViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_contato, parent, false) return ContatoViewHolder(view) } override fun onBindViewHolder(holder: ContatoViewHolder, position: Int) { holder.bind(getItem(position)) } } Para usar o ListAdapter, basta chamar submitList:\nval adapter = ContatoListAdapter { contato -\u0026gt; Toast.makeText(this, \u0026#34;Clicou em: ${contato.nome}\u0026#34;, Toast.LENGTH_SHORT).show() } recyclerView.adapter = adapter // Submete a lista — DiffUtil calcula as diferenças automaticamente adapter.submitList(listaDeContatos) // Atualiza com nova lista adapter.submitList(novaLista) Passo 6: Tratamento de Cliques No exemplo acima já implementamos click handling via lambda no construtor do adapter. Aqui está um padrão mais completo com clique e clique longo:\nclass ContatoListAdapter( private val onItemClick: (Contato) -\u0026gt; Unit, private val onItemLongClick: (Contato) -\u0026gt; Boolean ) : ListAdapter\u0026lt;Contato, ContatoListAdapter.ContatoViewHolder\u0026gt;(ContatoDiffCallback()) { inner class ContatoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { // ... views init { itemView.setOnClickListener { val pos = bindingAdapterPosition if (pos != RecyclerView.NO_POSITION) onItemClick(getItem(pos)) } itemView.setOnLongClickListener { val pos = bindingAdapterPosition if (pos != RecyclerView.NO_POSITION) onItemLongClick(getItem(pos)) else false } } // ... bind() } // ... onCreateViewHolder, onBindViewHolder } Passo 7: Múltiplos View Types Quando a lista tem itens com layouts diferentes (por exemplo, cabeçalhos e itens normais), usamos múltiplos view types:\nsealed class ListItem { data class Cabecalho(val titulo: String) : ListItem() data class ContatoItem(val contato: Contato) : ListItem() } class MultiTypeAdapter : ListAdapter\u0026lt;ListItem, RecyclerView.ViewHolder\u0026gt;(MultiDiffCallback()) { companion object { const val TIPO_CABECALHO = 0 const val TIPO_CONTATO = 1 } override fun getItemViewType(position: Int): Int { return when (getItem(position)) { is ListItem.Cabecalho -\u0026gt; TIPO_CABECALHO is ListItem.ContatoItem -\u0026gt; TIPO_CONTATO } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { val inflater = LayoutInflater.from(parent.context) return when (viewType) { TIPO_CABECALHO -\u0026gt; { val view = inflater.inflate(R.layout.item_cabecalho, parent, false) CabecalhoViewHolder(view) } TIPO_CONTATO -\u0026gt; { val view = inflater.inflate(R.layout.item_contato, parent, false) ContatoViewHolder(view) } else -\u0026gt; throw IllegalArgumentException(\u0026#34;View type desconhecido: $viewType\u0026#34;) } } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (val item = getItem(position)) { is ListItem.Cabecalho -\u0026gt; (holder as CabecalhoViewHolder).bind(item) is ListItem.ContatoItem -\u0026gt; (holder as ContatoViewHolder).bind(item.contato) } } } Passo 8: ItemDecoration para Separadores O ItemDecoration permite adicionar separadores, margens e outros elementos visuais sem alterar o layout dos itens:\nimport android.graphics.Canvas import android.graphics.Paint import android.graphics.Rect import android.view.View import androidx.recyclerview.widget.RecyclerView class DivisorDecoration( private val altura: Int = 2, private val cor: Int = 0xFFE0E0E0.toInt() ) : RecyclerView.ItemDecoration() { private val paint = Paint().apply { color = cor } override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { outRect.bottom = altura // espaço abaixo de cada item } override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { for (i in 0 until parent.childCount - 1) { val child = parent.getChildAt(i) val top = child.bottom.toFloat() c.drawRect( child.left.toFloat(), top, child.right.toFloat(), top + altura, paint ) } } } // Uso: recyclerView.addItemDecoration(DivisorDecoration()) // Ou use o DividerItemDecoration padrao do AndroidX: recyclerView.addItemDecoration( DividerItemDecoration(this, DividerItemDecoration.VERTICAL) ) Erros Comuns Usar notifyDataSetChanged() em vez de DiffUtil: Isso destrói todas as animações e recria todos os itens. Sempre prefira ListAdapter com DiffUtil para listas que mudam frequentemente.\nAcessar adapterPosition no momento errado: A posição pode ser RecyclerView.NO_POSITION durante animações. Sempre verifique antes de usar.\nCriar objetos dentro de onBindViewHolder: Este método é chamado muitas vezes. Evite criar listeners, formatadores ou outros objetos aqui — mova-os para onCreateViewHolder ou para o init do ViewHolder.\nEsquecer setHasFixedSize(true): Se todos os itens da lista têm o mesmo tamanho, ativar isso melhora significativamente a performance.\nSubmeter a mesma referência de lista ao ListAdapter: O DiffUtil compara referências. Se você modificar a lista original e submeter novamente, nada será atualizado. Sempre crie uma nova lista com toList() ou listOf().\nNão usar View Binding ou ViewBinding: Acessar views via findViewById repetidamente é ineficiente e propenso a erros. Considere usar View Binding para segurança de tipos.\nConclusão e Próximos Passos Neste tutorial, você aprendeu a implementar o RecyclerView com Kotlin do básico ao avançado: criação do Adapter e ViewHolder, configuração de diferentes LayoutManagers, atualizações eficientes com DiffUtil e ListAdapter, tratamento de cliques com lambdas, múltiplos view types usando sealed classes, e personalização visual com ItemDecoration.\nComo próximos passos, recomendamos:\nExplorar o Jetpack Compose como alternativa declarativa para listas com LazyColumn Aprender sobre paginação com a biblioteca Paging 3 para listas muito grandes Implementar swipe-to-delete e drag-and-drop com ItemTouchHelper Integrar o RecyclerView com MVVM para observar mudanças nos dados automaticamente Consultar o glossário de data class e lambda para reforçar conceitos usados neste tutorial O RecyclerView continua sendo fundamental no desenvolvimento Android, e dominar suas funcionalidades avançadas é um diferencial importante na sua carreira.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-recyclerview-tutorial/","summary":"\u003cp\u003eNeste tutorial, você vai aprender a implementar o \u003cstrong\u003eRecyclerView\u003c/strong\u003e no Android usando Kotlin, desde a configuração básica até técnicas avançadas como DiffUtil, ListAdapter, múltiplos view types e tratamento de cliques. O RecyclerView é o componente mais importante para exibir listas no Android, e dominá-lo é essencial para qualquer desenvolvedor Android.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-o-recyclerview\"\u003eO que é o RecyclerView?\u003c/h2\u003e\n\u003cp\u003eO RecyclerView é um componente do AndroidX que exibe grandes conjuntos de dados de forma eficiente, reciclando views que saem da tela para reutilizá-las com novos dados. Ele substitui o antigo ListView e oferece muito mais flexibilidade através de três componentes principais:\u003c/p\u003e","title":"RecyclerView com Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"O Jetpack Compose revolucionou a forma como construimos interfaces no Android. Abandonando o sistema de XML que dominou a plataforma por mais de uma decada, o Compose adota um paradigma declarativo onde a UI e descrita como funções Kotlin puras. Em vez de manipular views imperativamente, você declara como a tela deve parecer para cada estado, é o framework cuida das atualizações automaticamente. Este guia apresenta tudo o que você precisa saber para dominar o Jetpack Compose, desde conceitos fundamentais até padrões avançados usados em producao.\nPrimeiros Passos com Compose Para utilizar o Compose, adicione as dependências necessarias ao build.gradle.kts:\nandroid { buildFeatures { compose = true } composeOptions { kotlinCompilerExtensionVersion = \u0026#34;1.5.8\u0026#34; } } dependencies { val composeBom = platform(\u0026#34;androidx.compose:compose-bom:2024.02.00\u0026#34;) implementation(composeBom) implementation(\u0026#34;androidx.compose.ui:ui\u0026#34;) implementation(\u0026#34;androidx.compose.material3:material3\u0026#34;) implementation(\u0026#34;androidx.compose.ui:ui-tooling-preview\u0026#34;) implementation(\u0026#34;androidx.activity:activity-compose:1.8.2\u0026#34;) debugImplementation(\u0026#34;androidx.compose.ui:ui-tooling\u0026#34;) } Composables Fundamentais No Compose, cada elemento de UI e uma função anotada com @Composable. Os componentes básicos incluem Text, Button, Image, TextField e layouts como Column, Row e Box:\n@Composable fun CartaoProduto( nome: String, preco: Double, onComprarClick: () -\u0026gt; Unit ) { Card( modifier = Modifier .fillMaxWidth() .padding(16.dp), elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) ) { Column( modifier = Modifier.padding(16.dp) ) { Text( text = nome, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold ) Spacer(modifier = Modifier.height(8.dp)) Text( text = \u0026#34;R$ %.2f\u0026#34;.format(preco), style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.primary ) Spacer(modifier = Modifier.height(16.dp)) Button( onClick = onComprarClick, modifier = Modifier.fillMaxWidth() ) { Text(\u0026#34;Adicionar ao Carrinho\u0026#34;) } } } } Cada composable recebe parametros e renderiza a UI correspondente. Nao há heranca ou XML envolvido \u0026ndash; tudo e Kotlin.\nQuando a tela precisa incorporar APIs antigas de View, como preview de câmera, o padrão é usar AndroidView; veja um exemplo completo em CameraX com Compose e Kotlin.\nGerenciamento de Estado O estado e o conceito mais importante do Compose. Quando o estado muda, o Compose recompoe (re-renderiza) apenas os composables afetados:\n@Composable fun ContadorSimples() { var contador by remember { mutableStateOf(0) } Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(32.dp) ) { Text( text = \u0026#34;Contagem: $contador\u0026#34;, style = MaterialTheme.typography.displayMedium ) Spacer(modifier = Modifier.height(16.dp)) Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { Button(onClick = { contador-- }) { Text(\u0026#34;Diminuir\u0026#34;) } Button(onClick = { contador++ }) { Text(\u0026#34;Aumentar\u0026#34;) } } } } O remember preserva o estado entre recomposicoes, enquanto mutableStateOf cria um estado observavel. Para preservar o estado entre mudancas de configuração, use rememberSaveable.\nState Hoisting O padrão state hoisting consiste em elevar o estado para o composable pai, tornando os filhos stateless e reutilizaveis:\n@Composable fun FormularioCadastro() { var nome by rememberSaveable { mutableStateOf(\u0026#34;\u0026#34;) } var email by rememberSaveable { mutableStateOf(\u0026#34;\u0026#34;) } var senhaVisivel by remember { mutableStateOf(false) } FormularioConteudo( nome = nome, onNomeChange = { nome = it }, email = email, onEmailChange = { email = it }, senhaVisivel = senhaVisivel, onToggleSenha = { senhaVisivel = !senhaVisivel } ) } @Composable fun FormularioConteudo( nome: String, onNomeChange: (String) -\u0026gt; Unit, email: String, onEmailChange: (String) -\u0026gt; Unit, senhaVisivel: Boolean, onToggleSenha: () -\u0026gt; Unit ) { Column(modifier = Modifier.padding(16.dp)) { OutlinedTextField( value = nome, onValueChange = onNomeChange, label = { Text(\u0026#34;Nome completo\u0026#34;) }, modifier = Modifier.fillMaxWidth() ) Spacer(modifier = Modifier.height(8.dp)) OutlinedTextField( value = email, onValueChange = onEmailChange, label = { Text(\u0026#34;E-mail\u0026#34;) }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Email ), modifier = Modifier.fillMaxWidth() ) } } O FormularioConteudo e totalmente reutilizavel e testavel, pois não gerencia estado próprio.\nListas com LazyColumn O equivalente ao RecyclerView no Compose e o LazyColumn, que renderiza apenas os itens visiveis:\n@Composable fun ListaProdutos( produtos: List\u0026lt;Produto\u0026gt;, onProdutoClick: (Produto) -\u0026gt; Unit ) { LazyColumn( contentPadding = PaddingValues(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { items( items = produtos, key = { it.id } ) { produto -\u0026gt; CartaoProduto( nome = produto.nome, preco = produto.preco, onComprarClick = { onProdutoClick(produto) } ) } } } O parametro key e fundamental para performance, pois ajuda o Compose a identificar quais itens mudaram, foram adicionados ou removidos.\nNavegação no Compose O Navigation Compose permite navegação entre telas de forma declarativa:\n@Composable fun AppNavigation() { val navController = rememberNavController() NavHost( navController = navController, startDestination = \u0026#34;lista\u0026#34; ) { composable(\u0026#34;lista\u0026#34;) { TelaLista( onProdutoClick = { produtoId -\u0026gt; navController.navigate(\u0026#34;detalhe/$produtoId\u0026#34;) } ) } composable( route = \u0026#34;detalhe/{produtoId}\u0026#34;, arguments = listOf( navArgument(\u0026#34;produtoId\u0026#34;) { type = NavType.LongType } ) ) { backStackEntry -\u0026gt; val produtoId = backStackEntry.arguments?.getLong(\u0026#34;produtoId\u0026#34;) ?: 0L TelaDetalhe( produtoId = produtoId, onVoltarClick = { navController.popBackStack() } ) } } } Integração com ViewModel Compose se integra naturalmente com ViewModels e StateFlow:\n@Composable fun TelaProdutos( viewModel: ProdutoViewModel = hiltViewModel() ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() when (val state = uiState) { is ProdutoUiState.Loading -\u0026gt; { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { CircularProgressIndicator() } } is ProdutoUiState.Success -\u0026gt; { ListaProdutos( produtos = state.produtos, onProdutoClick = { viewModel.selecionarProduto(it) } ) } is ProdutoUiState.Error -\u0026gt; { MensagemErro( mensagem = state.mensagem, onTentarNovamente = { viewModel.carregarProdutos() } ) } } } O collectAsStateWithLifecycle e a forma recomendada de coletar Flows no Compose, pois respeita o ciclo de vida.\nTemas e Material Design 3 O Compose integra nativamente com Material Design 3, permitindo personalizar cores, tipografia e formas:\n@Composable fun MeuAppTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -\u0026gt; Unit ) { val colorScheme = if (darkTheme) { darkColorScheme( primary = Color(0xFF7C4DFF), secondary = Color(0xFF03DAC5), background = Color(0xFF121212) ) } else { lightColorScheme( primary = Color(0xFF6200EE), secondary = Color(0xFF03DAC5), background = Color(0xFFFFFBFE) ) } MaterialTheme( colorScheme = colorScheme, typography = Typography(), content = content ) } Boas Práticas com Jetpack Compose Composables pequenos e focados: cada composable deve ter uma única responsabilidade. Quebre telas complexas em componentes menores. State hoisting sempre que possível: composables stateless são mais reutilizaveis e testáveis. Use key em LazyColumn: sem keys, o Compose pode recompor itens incorretamente ao inserir ou remover elementos. Evite efeitos colaterais em composables: use LaunchedEffect, SideEffect ou DisposableEffect para operações que não são puras. Prefira Modifier como primeiro parametro opcional: e uma convencao do Compose que permite composição flexivel de estilos. Extraia preview functions: crie funções @Preview separadas para visualizar componentes no Android Studio sem rodar o app. Erros Comuns e Armadilhas Recomposicao excessiva: passar lambdas não estabilizadas ou objetos que mudam referência a cada recomposicao causa recomposicoes desnecessarias. Use remember para estabilizar callbacks. Esquecer o remember: sem remember, o estado e resetado a cada recomposicao, causando bugs dificeis de rastrear. Modificar estado durante a composição: alterar mutableStateOf dentro do corpo de um composable sem estar em um callback causa loops infinitos de recomposicao. Usar indices como keys: em LazyColumn, usar o indice da lista como key impede otimizações e causa comportamento incorreto quando itens são reordenados. Nao tratar loading e error states: toda tela que carrega dados deve ter estados visuais para carregamento e erro, melhorando a experiência do usuário. Conclusão e Próximos Passos O Jetpack Compose representa o futuro do desenvolvimento de interfaces no Android. Sua abordagem declarativa, combinada com a expressividade do Kotlin, resulta em código mais conciso, legivel é fácil de manter. Dominar conceitos como gerenciamento de estado, recomposicao e state hoisting e essencial para construir aplicações eficientes.\nComo próximos passos, explore animacoes no Compose, aprofunde-se em testes de UI com ComposeTestRule e estude a integração com Compose Multiplatform para compartilhar UI entre Android, iOS e desktop. Cada passo amplia as possibilidades do que você pode construir com essa tecnologia.\n","permalink":"https://kotlin.dev.br/guias/guia-jetpack-compose/","summary":"\u003cp\u003eO Jetpack Compose revolucionou a forma como construimos interfaces no Android. Abandonando o sistema de XML que dominou a plataforma por mais de uma decada, o Compose adota um paradigma declarativo onde a UI e descrita como funções Kotlin puras. Em vez de manipular views imperativamente, você declara como a tela deve parecer para cada estado, é o framework cuida das atualizações automaticamente. Este guia apresenta tudo o que você precisa saber para dominar o Jetpack Compose, desde conceitos fundamentais até padrões avançados usados em producao.\u003c/p\u003e","title":"Jetpack Compose: Guia Completo em Português | Kotlin Brasil"},{"content":"A arquitetura MVVM (Model-View-ViewModel) se consolidou como o padrão mais adotado no desenvolvimento Android moderno, especialmente quando combinada com Kotlin e os componentes do Jetpack. Diferente de abordagens mais antigas como MVC, o MVVM promove uma separação clara de responsabilidades que resulta em código mais testavel, manutenivel e resiliente a mudancas de configuração. Neste guia, vamos dissecar cada camada do MVVM, implementar exemplos práticos e explorar as melhores estrategias para projetos do mundo real.\nO Que é a Arquitetura MVVM O MVVM divide a aplicação em tres camadas distintas. A camada Model representa os dados é a lógica de negocios, incluindo repositórios, fontes de dados e entidades. A camada View e responsavel pela interface grafica \u0026ndash; Activities, Fragments ou composables no Jetpack Compose. A camada ViewModel atua como intermediaria, expondo dados da Model para a View de forma reativa e gerenciando o estado da interface.\nO fluxo de dados e unidirecional: a View observa o ViewModel, que por sua vez consulta a Model. A View nunca acessa a Model diretamente, é a Model não conhece nem a View nem o ViewModel. Essa separação facilita testes unitarios, pois cada camada pode ser testada de forma isolada.\nEstrutura de Pastas Recomendada Uma organizacao clara de pastas facilita a navegação e manutenção do projeto:\n// Estrutura de pacotes recomendada // com.exemplo.app/ // data/ // model/ -\u0026gt; Entidades e data classes // repository/ -\u0026gt; Repositórios // remote/ -\u0026gt; API services (Retrofit) // local/ -\u0026gt; DAOs e banco de dados (Room) // ui/ // lista/ -\u0026gt; ListaFragment + ListaViewModel // detalhe/ -\u0026gt; DetalheFragment + DetalheViewModel // di/ -\u0026gt; Modulos de injeção de dependencia // util/ -\u0026gt; Classes utilitarias Essa organizacao por featuré fácilita o crescimento do projeto e torna claro onde cada componente se encontra.\nA Camada Model A Model encapsula os dados e as regras de negócio. Vamos criar um exemplo completo com uma entidade, um serviço de API e um repositório:\n// Entidade de dominio data class Tarefa( val id: Long, val titulo: String, val descricao: String, val concluida: Boolean = false, val criadaEm: LocalDateTime = LocalDateTime.now() ) // Interface do serviço de API interface TarefaApiService { @GET(\u0026#34;tarefas\u0026#34;) suspend fun listarTarefas(): List\u0026lt;TarefaDto\u0026gt; @POST(\u0026#34;tarefas\u0026#34;) suspend fun criarTarefa(@Body tarefa: TarefaDto): TarefaDto @PUT(\u0026#34;tarefas/{id}\u0026#34;) suspend fun atualizarTarefa( @Path(\u0026#34;id\u0026#34;) id: Long, @Body tarefa: TarefaDto ): TarefaDto } // Repository que unifica fontes de dados class TarefaRepository( private val apiService: TarefaApiService, private val tarefaDao: TarefaDao ) { fun observarTarefas(): Flow\u0026lt;List\u0026lt;Tarefa\u0026gt;\u0026gt; { return tarefaDao.listarTodas().map { entidades -\u0026gt; entidades.map { it.toDomain() } } } suspend fun sincronizar() { val tarefasRemotas = apiService.listarTarefas() tarefaDao.inserirTodas(tarefasRemotas.map { it.toEntity() }) } suspend fun criarTarefa(tarefa: Tarefa) { val dto = tarefa.toDto() val resposta = apiService.criarTarefa(dto) tarefaDao.inserir(resposta.toEntity()) } } O Repository e o ponto central que decide de onde buscar os dados \u0026ndash; cache local, rede ou ambos. Essa abstração permite trocar a implementação sem afetar o restante da aplicação.\nA Camada ViewModel O ViewModel gerencia o estado da UI e sobrevive a mudancas de configuração. Com Kotlin, podemos usar tanto LiveData quanto StateFlow:\nclass TarefaViewModel( private val repository: TarefaRepository ) : ViewModel() { // Estado da UI usando StateFlow private val _uiState = MutableStateFlow\u0026lt;TarefaUiState\u0026gt;(TarefaUiState.Loading) val uiState: StateFlow\u0026lt;TarefaUiState\u0026gt; = _uiState.asStateFlow() // Evento unico (navegação, snackbar, etc.) private val _evento = Channel\u0026lt;TarefaEvento\u0026gt;() val evento = _evento.receiveAsFlow() init { carregarTarefas() } fun carregarTarefas() { viewModelScope.launch { _uiState.value = TarefaUiState.Loading try { repository.sincronizar() repository.observarTarefas().collect { tarefas -\u0026gt; _uiState.value = TarefaUiState.Success(tarefas) } } catch (e: Exception) { _uiState.value = TarefaUiState.Error( e.message ?: \u0026#34;Erro desconhecido\u0026#34; ) } } } fun criarTarefa(titulo: String, descricao: String) { viewModelScope.launch { try { val novaTarefa = Tarefa( id = 0, titulo = titulo, descricao = descricao ) repository.criarTarefa(novaTarefa) _evento.send(TarefaEvento.TarefaCriada) } catch (e: Exception) { _evento.send( TarefaEvento.Erro(\u0026#34;Falha ao criar tarefa\u0026#34;) ) } } } fun alternarConclusao(tarefa: Tarefa) { viewModelScope.launch { val atualizada = tarefa.copy(concluida = !tarefa.concluida) repository.criarTarefa(atualizada) } } } // Sealed class para estados da UI sealed class TarefaUiState { object Loading : TarefaUiState() data class Success(val tarefas: List\u0026lt;Tarefa\u0026gt;) : TarefaUiState() data class Error(val mensagem: String) : TarefaUiState() } // Sealed class para eventos unicos sealed class TarefaEvento { object TarefaCriada : TarefaEvento() data class Erro(val mensagem: String) : TarefaEvento() } A distincao entre estado (StateFlow) e evento (Channel) e fundamental. O estado pode ser re-observado a qualquer momento, enquanto eventos como navegação ou mensagens de snackbar devem ser consumidos uma única vez.\nA Camada View A View observa o ViewModel e reage as mudancas de estado:\nclass TarefaFragment : Fragment(R.layout.fragment_tarefa) { private val viewModel: TarefaViewModel by viewModels() private var _binding: FragmentTarefaBinding? = null private val binding get() = _binding!! private lateinit var adapter: TarefaAdapter override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) _binding = FragmentTarefaBinding.bind(view) configurarRecyclerView() observarEstado() observarEventos() binding.fabNovaTarefa.setOnClickListener { mostrarDialogNovaTarefa() } } private fun configurarRecyclerView() { adapter = TarefaAdapter { tarefa -\u0026gt; viewModel.alternarConclusao(tarefa) } binding.recyclerTarefas.adapter = adapter binding.recyclerTarefas.layoutManager = LinearLayoutManager(requireContext()) } private fun observarEstado() { viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { state -\u0026gt; when (state) { is TarefaUiState.Loading -\u0026gt; { binding.progressBar.isVisible = true binding.recyclerTarefas.isVisible = false } is TarefaUiState.Success -\u0026gt; { binding.progressBar.isVisible = false binding.recyclerTarefas.isVisible = true adapter.submitList(state.tarefas) } is TarefaUiState.Error -\u0026gt; { binding.progressBar.isVisible = false Snackbar.make( binding.root, state.mensagem, Snackbar.LENGTH_LONG ).show() } } } } } } private fun observarEventos() { viewLifecycleOwner.lifecycleScope.launch { viewModel.evento.collect { evento -\u0026gt; when (evento) { is TarefaEvento.TarefaCriada -\u0026gt; { Snackbar.make( binding.root, \u0026#34;Tarefa criada!\u0026#34;, Snackbar.LENGTH_SHORT ).show() } is TarefaEvento.Erro -\u0026gt; { Snackbar.make( binding.root, evento.mensagem, Snackbar.LENGTH_LONG ).show() } } } } } override fun onDestroyView() { super.onDestroyView() _binding = null } } O uso de repeatOnLifecycle garante que a coleta do Flow respeite o ciclo de vida do Fragment, evitando processamento desnecessário quando a tela não esta visivel.\nStateFlow vs LiveData Ambos servem para expor estado reativo, mas possuem diferenças importantes. O LiveData e lifecycle-aware por padrão e foi projetado especificamente para Android. O StateFlow faz parte das Coroutines e e mais flexivel, podendo ser usado em camadas que não dependem do Android SDK.\nA recomendacao atual do Google e usar StateFlow em ViewModels modernos, especialmente em projetos que utilizam Jetpack Compose, onde a integração com Flow e nativa.\nBoas Práticas para MVVM com Kotlin Mantenha o ViewModel livre de referências ao Android: não passe Context, View ou Activity para o ViewModel. Use AndroidViewModel apenas quando estritamente necessário. Use sealed classes para estados: elas garantem que todos os estados possiveis sejam tratados no when. Separe estado de eventos: use StateFlow para estado e Channel ou SharedFlow para eventos unicos. Injete dependências: nunca instancie repositórios diretamente no ViewModel. Use Hilt, Koin ou outra solução de injeção. Evite lógica de negócio na View: a View deve apenas observar e renderizar. Toda lógica pertence ao ViewModel ou a camada de dominio. Teste o ViewModel isoladamente: com dependências injetadas, basta criar mocks dos repositórios para testar toda a lógica. Erros Comuns e Armadilhas Coletar Flow sem respeitar o lifecycle: usar lifecycleScope.launch diretamente sem repeatOnLifecycle pode causar coleta em background desnecessaria e crashes. ViewModel fazendo chamadas diretas a API: o ViewModel deve delegar ao Repository, nunca chamar serviços de rede diretamente. Estado mutavel exposto: expor MutableStateFlow ou MutableLiveData publicamente permite que a View altere o estado diretamente, quebrando o fluxo unidirecional. Sempre exponha a versão imutavel. Excesso de ViewModels: não crie um ViewModel para cada componente pequeno. Um ViewModel por tela geralmente e suficiente. Ignorar tratamento de erros: sempre encapsule chamadas assíncronas em try-catch e comunique erros através do estado da UI. Conclusão e Próximos Passos A arquitetura MVVM com Kotlin proporciona uma base solida para aplicações Android de qualquer escala. A separação entre Model, View é ViewModel resulta em código mais organizado, testavel e resistente a mudancas. Com o uso de StateFlow, sealed classes e coroutines, o Kotlin torna a implementação do MVVM elegante e eficiente.\nPara evoluir ainda mais, explore Clean Architecture para adicionar uma camada de dominio ao MVVM, estude Jetpack Compose para interfaces declarativas e implemente testes unitarios completos para seus ViewModels. Esses topicos possuem guias dedicados aqui no Kotlin Brasil e vao complementar o conhecimento adquirido neste artigo.\n","permalink":"https://kotlin.dev.br/guias/guia-arquitetura-mvvm-kotlin/","summary":"\u003cp\u003eA arquitetura MVVM (Model-View-ViewModel) se consolidou como o padrão mais adotado no desenvolvimento Android moderno, especialmente quando combinada com Kotlin e os componentes do Jetpack. Diferente de abordagens mais antigas como MVC, o MVVM promove uma separação clara de responsabilidades que resulta em código mais testavel, manutenivel e resiliente a mudancas de configuração. Neste guia, vamos dissecar cada camada do MVVM, implementar exemplos práticos e explorar as melhores estrategias para projetos do mundo real.\u003c/p\u003e","title":"Arquitetura MVVM com Kotlin: Guia Completo em Português | Kotlin Brasil"},{"content":"Neste tutorial completo, você vai aprender tudo sobre Kotlin Flow, a API de programação reativa do Kotlin para lidar com fluxos de dados assíncronos. Vamos cobrir desde os conceitos fundamentais de cold streams até tópicos avançados como StateFlow, SharedFlow, operadores de transformação e tratamento de exceções. Ao final, você terá domínio suficiente para aplicar Flow em projetos Android e backend com confiança.\nO que é Kotlin Flow? O Flow é uma API da biblioteca kotlinx.coroutines que permite trabalhar com sequências de valores emitidos de forma assíncrona. Ele é classificado como um cold stream — isso significa que o código produtor só é executado quando existe um coletor (collector) consumindo os dados. Essa característica diferencia o Flow de outras abordagens como Channels, que são hot streams.\nPara quem vem do mundo RxJava, o Flow é a alternativa nativa do Kotlin para programação reativa, com a vantagem de ser muito mais leve, integrado com Coroutines e com tipagem segura graças ao sistema de tipos do Kotlin.\nPasso 1: Criando seu Primeiro Flow com o Builder O jeito mais comum de criar um Flow é usando o builder flow {}. Dentro dele, você usa a função suspend emit() para enviar valores ao coletor.\nimport kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking import kotlinx.coroutines.delay fun contagem(): Flow\u0026lt;Int\u0026gt; = flow { for (i in 1..5) { delay(500) // simula trabalho assíncrono emit(i) // emite o valor } } fun main() = runBlocking { contagem().collect { valor -\u0026gt; println(\u0026#34;Valor recebido: $valor\u0026#34;) } } Note que collect é uma função terminal — ela é suspend e bloqueia a coroutine atual até que o Flow termine de emitir todos os valores. O Flow respeita a structured concurrency, sendo cancelado automaticamente quando o escopo da coroutine é encerrado.\nExistem também builders simplificados para casos comuns:\n// Flow a partir de uma lista val flowDeLista = listOf(1, 2, 3).asFlow() // Flow com um unico valor val flowUnico = flowOf(\u0026#34;Olá, Kotlin Flow!\u0026#34;) // Flow vazio val flowVazio = emptyFlow\u0026lt;String\u0026gt;() Passo 2: Operadores Intermediários — map, filter e transform Assim como trabalhamos com Collections, o Flow oferece operadores intermediários que transformam os dados antes de chegarem ao coletor. Esses operadores retornam um novo Flow e são avaliados de forma preguiçosa (lazy).\nfun main() = runBlocking { (1..10).asFlow() .filter { it % 2 == 0 } // mantém apenas pares .map { it * it } // eleva ao quadrado .collect { println(it) } // 4, 16, 36, 64, 100 } O operador transform é mais flexível, permitindo emitir zero ou mais valores para cada item recebido:\nfun main() = runBlocking { (1..3).asFlow() .transform { valor -\u0026gt; emit(\u0026#34;Processando $valor...\u0026#34;) delay(300) emit(\u0026#34;Resultado: ${valor * 10}\u0026#34;) } .collect { println(it) } } Outros operadores úteis incluem take (limita quantidade de emissões), drop (ignora as primeiras N emissões), distinctUntilChanged (evita valores duplicados consecutivos) e onEach (executa uma ação para cada valor sem transformá-lo).\nPasso 3: Controlando o Contexto com flowOn Por padrão, o Flow executa no contexto da coroutine que chama collect. Mas e se você quiser que o código produtor rode em uma thread diferente? É aí que entra o operador flowOn.\nimport kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking fun dadosPesados(): Flow\u0026lt;Int\u0026gt; = flow { for (i in 1..5) { Thread.sleep(500) // simula operacao de I/O emit(i) println(\u0026#34;Emitindo em: ${Thread.currentThread().name}\u0026#34;) } }.flowOn(Dispatchers.IO) // muda o contexto do produtor fun main() = runBlocking { dadosPesados().collect { valor -\u0026gt; println(\u0026#34;Coletando $valor em: ${Thread.currentThread().name}\u0026#34;) } } O flowOn altera apenas o contexto upstream (do produtor), não do coletor. Isso mantém a previsibilidade do código e respeita o princípio de transparência de contexto do Flow.\nPasso 4: Buffer e Conflate para Performance Quando o produtor é mais rápido que o coletor, podemos usar buffer para permitir que eles executem concorrentemente, ou conflate para descartar valores intermediários e processar apenas o mais recente.\nimport kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking import kotlinx.coroutines.delay fun main() = runBlocking { val tempoInicio = System.currentTimeMillis() (1..5).asFlow() .onEach { delay(100) } // produtor emite a cada 100ms .buffer() // permite execucao concorrente .collect { valor -\u0026gt; delay(300) // coletor leva 300ms para processar val tempo = System.currentTimeMillis() - tempoInicio println(\u0026#34;$valor coletado em ${tempo}ms\u0026#34;) } } Com conflate, se o coletor estiver ocupado, valores intermediários são descartados:\n(1..5).asFlow() .onEach { delay(100) } .conflate() // descarta valores nao processados .collect { valor -\u0026gt; delay(300) println(\u0026#34;Processado: $valor\u0026#34;) // pode pular 2, 3, 4 } Passo 5: StateFlow e SharedFlow — Hot Streams Enquanto o Flow padrão é cold, o Kotlin oferece duas variantes hot para cenários onde múltiplos coletores precisam observar o mesmo fluxo de dados.\nStateFlow mantém sempre o valor mais recente e emite para novos coletores imediatamente. É ideal para representar estado em arquiteturas como MVVM.\nimport kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.delay fun main() = runBlocking { val estado = MutableStateFlow(0) // valor inicial obrigatório // Coletor 1 val job1 = launch { estado.collect { println(\u0026#34;Coletor 1: $it\u0026#34;) } } delay(100) estado.value = 1 delay(100) estado.value = 2 // Coletor 2 recebe imediatamente o valor atual (2) val job2 = launch { estado.collect { println(\u0026#34;Coletor 2: $it\u0026#34;) } } delay(100) estado.value = 3 delay(200) job1.cancel() job2.cancel() } SharedFlow é mais flexível — permite configurar replay (quantos valores anteriores novos coletores recebem) e não exige valor inicial:\nval eventos = MutableSharedFlow\u0026lt;String\u0026gt;( replay = 1, // novos coletores recebem o último evento extraBufferCapacity = 5 ) // Emitir valor eventos.emit(\u0026#34;Evento A\u0026#34;) // Ou de forma nao-suspensa (pode falhar se o buffer estiver cheio) eventos.tryEmit(\u0026#34;Evento B\u0026#34;) Passo 6: Tratamento de Exceções com catch O operador catch intercepta exceções que ocorrem upstream no Flow. Ele não captura erros no collect, apenas nos operadores e no produtor acima dele na cadeia.\nfun fluxoComErro(): Flow\u0026lt;Int\u0026gt; = flow { emit(1) emit(2) throw RuntimeException(\u0026#34;Algo deu errado!\u0026#34;) emit(3) // nunca será alcançado } fun main() = runBlocking { fluxoComErro() .catch { e -\u0026gt; println(\u0026#34;Erro capturado: ${e.message}\u0026#34;) emit(-1) // pode emitir um valor de fallback } .collect { println(\u0026#34;Valor: $it\u0026#34;) } // Saída: Valor: 1, Valor: 2, Erro capturado: Algo deu errado!, Valor: -1 } Para capturar erros no collect, use onEach junto com catch e launchIn:\nfluxoComErro() .onEach { valor -\u0026gt; println(\u0026#34;Processando: $valor\u0026#34;) } .catch { e -\u0026gt; println(\u0026#34;Erro: ${e.message}\u0026#34;) } .launchIn(this) // equivale a launch { flow.collect() } Você também pode usar onCompletion para executar código quando o Flow termina, independentemente de ter ocorrido erro:\n(1..3).asFlow() .onCompletion { causa -\u0026gt; if (causa != null) println(\u0026#34;Terminou com erro: $causa\u0026#34;) else println(\u0026#34;Flow completado com sucesso\u0026#34;) } .collect { println(it) } Erros Comuns Emitir valores de outro contexto sem flowOn: Nunca use withContext dentro do builder flow {} para mudar o dispatcher. O Flow proíbe isso e lança uma IllegalStateException. Use flowOn em vez disso.\nEsquecer que collect é suspend: O collect suspende a coroutine. Se você precisa coletar sem bloquear, use launchIn(scope) em vez de collect.\nConfundir StateFlow com LiveData: O StateFlow sempre emite o valor atual para novos coletores, mas diferente do LiveData, ele não é lifecycle-aware. No Android, use repeatOnLifecycle ou flowWithLifecycle para coletar de forma segura.\nNão tratar backpressure: Se o produtor é muito mais rápido que o consumidor e você não usa buffer ou conflate, o coletor será o gargalo e o Flow ficará lento.\nUsar SharedFlow sem buffer adequado: Se o extraBufferCapacity for 0 e nenhum coletor estiver ativo, chamadas a emit() vão suspender indefinidamente. Configure o buffer conforme sua necessidade.\nIgnorar o cancelamento: Flows respeitam o cancelamento cooperativo de coroutines. Se você usar operações bloqueantes (como Thread.sleep) em vez de delay, o cancelamento não funcionará corretamente.\nConclusão e Próximos Passos Neste tutorial, você aprendeu os fundamentos e técnicas avançadas do Kotlin Flow: desde a criação de cold streams com o builder flow {}, passando por operadores de transformação como map, filter e transform, controle de contexto com flowOn, otimização de performance com buffer e conflate, hot streams com StateFlow e SharedFlow, até o tratamento robusto de exceções com catch.\nO Flow é uma peça central no ecossistema Kotlin moderno e se integra perfeitamente com frameworks como Jetpack Compose, Room e Retrofit. Como próximos passos, recomendamos:\nExplorar a integração de Flow com Room Database para observar mudanças no banco de dados em tempo real Aprender sobre o padrão MVVM usando StateFlow no ViewModel Praticar combinando múltiplos Flows com operadores como combine, zip e merge Consultar o glossário de Flow e Coroutines para reforçar conceitos Dominar o Kotlin Flow é um diferencial importante para qualquer desenvolvedor que trabalhe com Kotlin, seja no Android ou no backend.\n","permalink":"https://kotlin.dev.br/tutoriais/kotlin-flow-tutorial/","summary":"\u003cp\u003eNeste tutorial completo, você vai aprender tudo sobre \u003cstrong\u003eKotlin Flow\u003c/strong\u003e, a API de programação reativa do Kotlin para lidar com fluxos de dados assíncronos. Vamos cobrir desde os conceitos fundamentais de cold streams até tópicos avançados como \u003ca href=\"/glossario/flow/\"\u003eStateFlow\u003c/a\u003e, SharedFlow, operadores de transformação e tratamento de exceções. Ao final, você terá domínio suficiente para aplicar Flow em projetos Android e backend com confiança.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-kotlin-flow\"\u003eO que é Kotlin Flow?\u003c/h2\u003e\n\u003cp\u003eO \u003ca href=\"/glossario/flow/\"\u003eFlow\u003c/a\u003e é uma API da biblioteca \u003ccode\u003ekotlinx.coroutines\u003c/code\u003e que permite trabalhar com sequências de valores emitidos de forma assíncrona. Ele é classificado como um \u003cstrong\u003ecold stream\u003c/strong\u003e — isso significa que o código produtor só é executado quando existe um coletor (collector) consumindo os dados. Essa característica diferencia o Flow de outras abordagens como Channels, que são hot streams.\u003c/p\u003e","title":"Kotlin Flow Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"O ecossistema Kotlin nunca esteve tão vibrante. Com o Kotlin Multiplatform atingindo estabilidade, o Compose Multiplatform evoluindo rapidamente e novas fronteiras como WASM e server-side ganhando tração, 2026 promete ser um ano transformador. Vamos explorar as principais tendências que vão moldar o futuro do Kotlin.\nKotlin Multiplatform Maduro e Estável O Kotlin Multiplatform (KMP) saiu de beta e agora é considerado estável para produção. Em 2026, vemos uma adoção crescente em empresas de todos os portes.\n// KMP - Compartilhamento de lógica de negócios // commonMain class AuthUseCase( private val authRepository: AuthRepository, private val tokenStorage: TokenStorage ) { suspend fun login(email: String, senha: String): Result\u0026lt;User\u0026gt; { return authRepository.authenticate(email, senha) .onSuccess { user -\u0026gt; tokenStorage.saveToken(user.accessToken) } } suspend fun isAuthenticated(): Boolean { val token = tokenStorage.getToken() ?: return false return !token.isExpired() } } A tendência é que empresas que antes resistiam ao KMP por ser experimental agora adotem rapidamente. Netflix, Philips, Cash App e muitas outras já usam KMP em produção, e a lista só cresce.\nExpect/Actual Cada Vez Mais Simples A mecânica de expect/actual está ficando mais intuitiva, com a JetBrains trabalhando em formas de reduzir boilerplate:\n// commonMain expect class PlatformLogger() { fun info(message: String) fun error(message: String, throwable: Throwable? = null) } // androidMain actual class PlatformLogger { actual fun info(message: String) { Log.i(\u0026#34;App\u0026#34;, message) } actual fun error(message: String, throwable: Throwable?) { Log.e(\u0026#34;App\u0026#34;, message, throwable) } } Compose Multiplatform Domina Compose Multiplatform está se consolidando como a solução definitiva para UI multiplataforma em Kotlin. Em 2026, o suporte para iOS está muito mais maduro, e muitas empresas já usam Compose para compartilhar não apenas lógica, mas também a interface.\n// Compose Multiplatform - UI compartilhada @Composable fun ProductList( products: List\u0026lt;Product\u0026gt;, onProductClick: (Product) -\u0026gt; Unit ) { LazyColumn( contentPadding = PaddingValues(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { items(products) { product -\u0026gt; ProductCard( product = product, onClick = { onProductClick(product) } ) } } } @Composable fun ProductCard( product: Product, onClick: () -\u0026gt; Unit ) { Card( modifier = Modifier .fillMaxWidth() .clickable(onClick = onClick) ) { Column(modifier = Modifier.padding(16.dp)) { Text( text = product.nome, style = MaterialTheme.typography.titleMedium ) Text( text = \u0026#34;R$ ${product.preco}\u0026#34;, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.primary ) } } } A grande vantagem sobre Flutter é que Compose Multiplatform permite misturar componentes nativos quando necessário, sem a necessidade de platform channels.\nKotlin/WASM Abre Novas Portas WebAssembly (WASM) é uma das fronteiras mais empolgantes para Kotlin. Com Kotlin/WASM, é possível rodar código Kotlin no navegador com performance próxima ao nativo.\n// Kotlin/WASM - Aplicação web @OptIn(ExperimentalComposeUiApi::class) fun main() { CanvasBasedWindow(\u0026#34;Minha App\u0026#34;) { MaterialTheme { var texto by remember { mutableStateOf(\u0026#34;\u0026#34;) } Column(modifier = Modifier.padding(16.dp)) { TextField( value = texto, onValueChange = { texto = it }, label = { Text(\u0026#34;Digite algo\u0026#34;) } ) Text(\u0026#34;Você digitou: $texto\u0026#34;) } } } } Isso significa que no futuro próximo, um desenvolvedor Kotlin pode criar aplicações para Android, iOS, desktop e web, tudo com a mesma linguagem e framework (Compose).\nServer-Side Kotlin em Ascensão O uso de Kotlin no backend continua crescendo, impulsionado por frameworks cada vez mais maduros.\nKtor 3.0 Ktor está evoluindo rapidamente, com melhorias em performance e developer experience:\n// Ktor com recursos modernos fun Application.module() { install(Resources) install(RateLimit) { register(RateLimitName(\u0026#34;api\u0026#34;)) { rateLimiter(limit = 100, refillPeriod = 60.seconds) } } routing { rateLimit(RateLimitName(\u0026#34;api\u0026#34;)) { route(\u0026#34;/api/v1\u0026#34;) { get\u0026lt;Produtos\u0026gt; { params -\u0026gt; val produtos = produtoService.listar( pagina = params.pagina, tamanho = params.tamanho, filtro = params.filtro ) call.respond(produtos) } } } } } @Resource(\u0026#34;/produtos\u0026#34;) data class Produtos( val pagina: Int = 1, val tamanho: Int = 20, val filtro: String? = null ) Spring Boot com Kotlin Spring Boot continua sendo o framework mais usado para Kotlin no backend enterprise, e a integração só melhora:\n// Spring Boot com coroutines nativas @RestController @RequestMapping(\u0026#34;/api/relatorios\u0026#34;) class RelatorioController( private val relatorioService: RelatorioService ) { @GetMapping(\u0026#34;/vendas\u0026#34;) suspend fun gerarRelatorioVendas( @RequestParam periodo: String, @RequestParam formato: String = \u0026#34;json\u0026#34; ): ResponseEntity\u0026lt;Flow\u0026lt;VendaDTO\u0026gt;\u0026gt; { val vendas = relatorioService.buscarVendas(periodo) return ResponseEntity.ok(vendas.map { it.toDTO() }) } } Inteligência Artificial e Kotlin Uma tendência crescente é o uso de Kotlin para integrações com IA. Bibliotecas como LangChain4j e Spring AI facilitam a criação de aplicações inteligentes:\n// Integração com LLMs usando Kotlin class AssistenteVirtual( private val chatModel: ChatLanguageModel, private val memoryStore: ChatMemoryStore ) { suspend fun responder(pergunta: String, sessionId: String): String { val memory = memoryStore.getMessages(sessionId) val response = withContext(Dispatchers.IO) { chatModel.generate( memory + UserMessage.from(pergunta) ) } memoryStore.addMessage(sessionId, response.content()) return response.content().text() } } Gradle com Kotlin DSL Como Padrão O Kotlin DSL para Gradle já é o padrão recomendado, e em 2026 praticamente todos os projetos novos o utilizam:\n// build.gradle.kts - Type-safe e com autocomplete plugins { kotlin(\u0026#34;jvm\u0026#34;) version \u0026#34;2.1.0\u0026#34; kotlin(\u0026#34;plugin.serialization\u0026#34;) version \u0026#34;2.1.0\u0026#34; id(\u0026#34;io.ktor.plugin\u0026#34;) version \u0026#34;3.0.0\u0026#34; } dependencies { implementation(libs.ktor.server.core) implementation(libs.ktor.server.netty) implementation(libs.kotlinx.serialization.json) implementation(libs.exposed.core) implementation(libs.exposed.dao) testImplementation(libs.ktor.server.test.host) testImplementation(libs.kotlin.test) } Kotlin para Educação Outra tendência forte é o uso crescente de Kotlin como linguagem de ensino em universidades e cursos. Sua sintaxe limpa, null safety e interoperabilidade com Java a tornam ideal para ensinar programação orientada a objetos e funcional.\nNo Brasil, cada vez mais bootcamps e cursos incluem Kotlin no currículo, não apenas para Android, mas como linguagem principal de backend.\nTendências de Mercado no Brasil O mercado brasileiro para Kotlin está aquecido em várias frentes:\nFintechs e bancos: Migrações de Java para Kotlin continuam em ritmo acelerado Startups: Adoção de KMP para otimizar times mobile Consultorias: Demanda por especialistas Kotlin em projetos de modernização Trabalho remoto: Empresas internacionais buscando desenvolvedores Kotlin brasileiros Salários para desenvolvedores Kotlin sênior no Brasil variam de R$ 15.000 a R$ 30.000 para posições CLT, podendo ultrapassar R$ 40.000 em contratos PJ com empresas internacionais.\nConclusão 2026 é o ano em que Kotlin se consolida como uma plataforma completa, não apenas uma linguagem. De mobile a backend, de desktop a web, o ecossistema Kotlin oferece soluções maduras e em constante evolução.\nPara desenvolvedores que querem se posicionar para o futuro, investir em Kotlin Multiplatform, Compose Multiplatform e server-side Kotlin são as apostas mais seguras. A linguagem está no centro de uma convergência tecnológica que promete simplificar radicalmente o desenvolvimento de software multiplataforma.\nFique de olho nessas tendências, participe da comunidade e experimente as novidades. No cenário de linguagens modernas, Kotlin compete e coopera com Go no backend cloud-native, Rust em sistemas de alta performance e Python em IA e data science. O ecossistema Kotlin está em plena expansão, e quem embarcar agora terá uma vantagem competitiva significativa nos próximos anos.\n","permalink":"https://kotlin.dev.br/blog/tendencias-kotlin-2026/","summary":"\u003cp\u003eO ecossistema Kotlin nunca esteve tão vibrante. Com o Kotlin Multiplatform atingindo estabilidade, o Compose Multiplatform evoluindo rapidamente e novas fronteiras como WASM e server-side ganhando tração, 2026 promete ser um ano transformador. Vamos explorar as principais tendências que vão moldar o futuro do Kotlin.\u003c/p\u003e\n\u003ch2 id=\"kotlin-multiplatform-maduro-e-estável\"\u003eKotlin Multiplatform Maduro e Estável\u003c/h2\u003e\n\u003cp\u003eO Kotlin Multiplatform (KMP) saiu de beta e agora é considerado estável para produção. Em 2026, vemos uma adoção crescente em empresas de todos os portes.\u003c/p\u003e","title":"Tendências Kotlin em 2026: O Que Esperar | Kotlin Brasil"},{"content":"Neste tutorial, você vai aprender os fundamentos de Coroutines em Kotlin — o mecanismo oficial da linguagem para programação assíncrona e concorrente. Coroutines permitem escrever código assíncrono de forma sequencial e legível, sem callbacks aninhados ou complexidade desnecessária. Ao final, você vai dominar suspend functions, launch, async/await, dispatchers, structured concurrency e os conceitos básicos de cancelamento.\nO que São Coroutines? Uma coroutine é uma instância de computação suspensível. Diferente de threads do sistema operacional, coroutines são extremamente leves — você pode criar milhares delas sem problemas de performance. Enquanto uma thread bloqueada consome recursos do sistema, uma coroutine suspensa libera a thread para fazer outro trabalho.\nPense em coroutines como funções que podem pausar sua execução em pontos específicos e retomar mais tarde, possivelmente em outra thread. Isso é perfeito para operações de I/O (rede, disco, banco de dados) que passam a maior parte do tempo esperando.\nConfigurando o Projeto Antes de usar coroutines, você precisa adicionar a dependência no seu build.gradle.kts:\ndependencies { implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3\u0026#34;) // Para Android, adicione tambem: // implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3\u0026#34;) } Suspend Functions Uma suspend function é uma função que pode ser pausada e retomada. Ela é marcada com a palavra-chave suspend:\nimport kotlinx.coroutines.* suspend fun buscarDadosDoServidor(): String { delay(2000) // Simula uma chamada de rede (2 segundos) return \u0026#34;Dados carregados com sucesso!\u0026#34; } suspend fun salvarNoCache(dados: String) { delay(500) // Simula escrita no cache println(\u0026#34;Cache atualizado: $dados\u0026#34;) } A função delay() é o equivalente suspensível de Thread.sleep() — ela pausa a coroutine sem bloquear a thread. Suspend functions só podem ser chamadas de dentro de outras suspend functions ou de coroutine builders.\nO importante é que suspend functions se parecem com código síncrono normal. Não há callbacks, não há .then(), não há observables encadeados. O código é lido de cima para baixo, como deveria ser.\nrunBlocking O runBlocking é o ponto de entrada mais simples para o mundo das coroutines. Ele bloqueia a thread atual até que todas as coroutines internas terminem:\nimport kotlinx.coroutines.* fun main() = runBlocking { println(\u0026#34;Início: ${Thread.currentThread().name}\u0026#34;) val dados = buscarDadosDoServidor() println(dados) salvarNoCache(dados) println(\u0026#34;Fim!\u0026#34;) } // Saída: // Início: main // Dados carregados com sucesso! // Cache atualizado: Dados carregados com sucesso! // Fim! Use runBlocking apenas em funções main() e em testes. Em código de produção (especialmente Android), você vai usar coroutine scopes apropriados.\nlaunch: Coroutines Fire-and-Forget O builder launch cria uma nova coroutine que roda de forma concorrente. Ele retorna um Job que pode ser usado para controlar a coroutine:\nimport kotlinx.coroutines.* fun main() = runBlocking { println(\u0026#34;Antes do launch\u0026#34;) val job = launch { println(\u0026#34;Coroutine iniciada\u0026#34;) delay(1000) println(\u0026#34;Coroutine finalizada\u0026#34;) } println(\u0026#34;Depois do launch — a coroutine está rodando em paralelo!\u0026#34;) job.join() // Espera a coroutine terminar println(\u0026#34;Tudo concluído\u0026#34;) } // Saída: // Antes do launch // Depois do launch — a coroutine está rodando em paralelo! // Coroutine iniciada // Coroutine finalizada // Tudo concluído Veja como várias coroutines rodam concorrentemente:\nfun main() = runBlocking { val inicio = System.currentTimeMillis() val job1 = launch { delay(1000) println(\u0026#34;Tarefa 1 completa\u0026#34;) } val job2 = launch { delay(1500) println(\u0026#34;Tarefa 2 completa\u0026#34;) } val job3 = launch { delay(800) println(\u0026#34;Tarefa 3 completa\u0026#34;) } // Todas rodam em paralelo! job1.join() job2.join() job3.join() val tempo = System.currentTimeMillis() - inicio println(\u0026#34;Total: ${tempo}ms\u0026#34;) // ~1500ms, NÃO 3300ms! } As três tarefas executam simultaneamente, então o tempo total é determinado pela tarefa mais lenta (1500ms), não pela soma de todas.\nasync/await: Coroutines com Retorno Enquanto launch é para tarefas \u0026ldquo;fire-and-forget\u0026rdquo;, async é para quando você precisa de um resultado. Ele retorna um Deferred\u0026lt;T\u0026gt;, e você obtém o valor com await():\nimport kotlinx.coroutines.* suspend fun buscarUsuario(): String { delay(1000) return \u0026#34;Ana Silva\u0026#34; } suspend fun buscarPedidos(): List\u0026lt;String\u0026gt; { delay(1500) return listOf(\u0026#34;Pedido #1\u0026#34;, \u0026#34;Pedido #2\u0026#34;, \u0026#34;Pedido #3\u0026#34;) } fun main() = runBlocking { val inicio = System.currentTimeMillis() // Executar as duas buscas em paralelo val usuarioDeferred = async { buscarUsuario() } val pedidosDeferred = async { buscarPedidos() } // Esperar os resultados val usuario = usuarioDeferred.await() val pedidos = pedidosDeferred.await() println(\u0026#34;Usuário: $usuario\u0026#34;) println(\u0026#34;Pedidos: $pedidos\u0026#34;) val tempo = System.currentTimeMillis() - inicio println(\u0026#34;Total: ${tempo}ms\u0026#34;) // ~1500ms (em paralelo) } Se as chamadas fossem sequenciais, levariam 2500ms (1000 + 1500). Com async, levam apenas ~1500ms porque rodam em paralelo. Isso é extremamente valioso em aplicações reais onde você precisa buscar dados de múltiplas fontes.\nCoroutine Scope Todo coroutine builder (launch, async) opera dentro de um scope. O scope define o ciclo de vida das coroutines:\nimport kotlinx.coroutines.* fun main() = runBlocking { // runBlocking cria um CoroutineScope // coroutineScope cria um sub-scope que espera todas as coroutines filhas coroutineScope { launch { delay(500) println(\u0026#34;Tarefa 1 do scope\u0026#34;) } launch { delay(300) println(\u0026#34;Tarefa 2 do scope\u0026#34;) } println(\u0026#34;Dentro do coroutineScope\u0026#34;) } println(\u0026#34;Depois do coroutineScope — todas as filhas terminaram\u0026#34;) } // Em codigo real (como no Android): class MinhaViewModel : ViewModel() { // viewModelScope é cancelado quando o ViewModel é destruído fun carregarDados() { viewModelScope.launch { val dados = buscarDadosDoServidor() // Atualizar UI } } } O coroutineScope é uma suspend function que cria um novo escopo e só retorna quando todas as coroutines filhas terminam. Se qualquer filha falhar, todas as outras são canceladas automaticamente.\nDispatchers Dispatchers determinam em qual thread (ou pool de threads) a coroutine será executada:\nimport kotlinx.coroutines.* fun main() = runBlocking { // Dispatchers.Default — para trabalho intensivo de CPU launch(Dispatchers.Default) { println(\u0026#34;Default: ${Thread.currentThread().name}\u0026#34;) // Cálculos pesados, processamento de dados, algoritmos val resultado = (1..1_000_000).sum() println(\u0026#34;Soma: $resultado\u0026#34;) } // Dispatchers.IO — para operacoes de I/O launch(Dispatchers.IO) { println(\u0026#34;IO: ${Thread.currentThread().name}\u0026#34;) // Chamadas de rede, leitura/escrita de arquivos, banco de dados delay(100) // Simula I/O } // Dispatchers.Main — para atualizar a UI (Android) // launch(Dispatchers.Main) { // textView.text = \u0026#34;Atualizado!\u0026#34; // } // Dispatchers.Unconfined — sem thread especifica (raro de usar) launch(Dispatchers.Unconfined) { println(\u0026#34;Unconfined: ${Thread.currentThread().name}\u0026#34;) } } Na prática, o padrão mais comum é:\n// Padrão Android típico viewModelScope.launch { // Main por padrao no Android val dados = withContext(Dispatchers.IO) { // Executar chamada de rede na thread de IO api.buscarDados() } // De volta na Main thread — seguro para atualizar UI atualizarTela(dados) } A função withContext() troca o dispatcher temporariamente e retorna ao dispatcher original quando termina.\nStructured Concurrency Structured concurrency é o princípio de que coroutines formam uma hierarquia pai-filho. Quando o scope pai é cancelado, todas as coroutines filhas são canceladas automaticamente:\nimport kotlinx.coroutines.* fun main() = runBlocking { val job = launch { // Coroutines filhas launch { repeat(10) { i -\u0026gt; println(\u0026#34;Filha 1: iteração $i\u0026#34;) delay(500) } } launch { repeat(10) { i -\u0026gt; println(\u0026#34;Filha 2: iteração $i\u0026#34;) delay(300) } } } delay(1200) // Deixa rodar por 1.2 segundos println(\u0026#34;Cancelando o pai...\u0026#34;) job.cancelAndJoin() // Cancela o pai E todas as filhas println(\u0026#34;Todas as coroutines foram canceladas\u0026#34;) } Isso garante que não existam coroutines \u0026ldquo;órfãs\u0026rdquo; rodando sem controle. É uma das vantagens mais importantes das coroutines sobre threads tradicionais.\nCancelamento de Coroutines Coroutines suportam cancelamento cooperativo. Funções suspensíveis da stdlib (delay, yield, withContext) verificam automaticamente se a coroutine foi cancelada:\nimport kotlinx.coroutines.* fun main() = runBlocking { val job = launch { try { repeat(100) { i -\u0026gt; println(\u0026#34;Processando item $i...\u0026#34;) delay(200) // Ponto de cancelamento } } catch (e: CancellationException) { println(\u0026#34;Coroutine cancelada! Limpando recursos...\u0026#34;) } finally { println(\u0026#34;Finally: cleanup executado\u0026#34;) } } delay(1000) println(\u0026#34;Solicitando cancelamento...\u0026#34;) job.cancelAndJoin() println(\u0026#34;Concluído\u0026#34;) } Para código que faz computação intensiva sem chamar funções suspensíveis, use isActive ou ensureActive():\nval job = launch(Dispatchers.Default) { var i = 0 while (isActive) { // Verifica se a coroutine ainda está ativa i++ // Trabalho intensivo de CPU if (i % 1000 == 0) println(\u0026#34;Iteração $i\u0026#34;) } println(\u0026#34;Loop encerrado em $i\u0026#34;) } delay(100) job.cancelAndJoin() Exemplo Prático Completo Vamos simular um cenário real — carregar dados de múltiplas fontes em paralelo:\nimport kotlinx.coroutines.* data class DashboardData( val usuario: String, val notificacoes: List\u0026lt;String\u0026gt;, val estatisticas: Map\u0026lt;String, Int\u0026gt; ) suspend fun buscarPerfil(): String { delay(800) return \u0026#34;Diego Oliveira\u0026#34; } suspend fun buscarNotificacoes(): List\u0026lt;String\u0026gt; { delay(1200) return listOf(\u0026#34;Nova mensagem\u0026#34;, \u0026#34;Pedido enviado\u0026#34;, \u0026#34;Promoção ativa\u0026#34;) } suspend fun buscarEstatisticas(): Map\u0026lt;String, Int\u0026gt; { delay(1000) return mapOf(\u0026#34;visitas\u0026#34; to 1500, \u0026#34;vendas\u0026#34; to 42, \u0026#34;avaliações\u0026#34; to 230) } suspend fun carregarDashboard(): DashboardData = coroutineScope { val perfilDeferred = async { buscarPerfil() } val notificacoesDeferred = async { buscarNotificacoes() } val estatisticasDeferred = async { buscarEstatisticas() } DashboardData( usuario = perfilDeferred.await(), notificacoes = notificacoesDeferred.await(), estatisticas = estatisticasDeferred.await() ) } fun main() = runBlocking { val inicio = System.currentTimeMillis() val dashboard = carregarDashboard() println(\u0026#34;Usuário: ${dashboard.usuario}\u0026#34;) println(\u0026#34;Notificações: ${dashboard.notificacoes}\u0026#34;) println(\u0026#34;Estatísticas: ${dashboard.estatisticas}\u0026#34;) val tempo = System.currentTimeMillis() - inicio println(\u0026#34;Carregado em ${tempo}ms\u0026#34;) // ~1200ms (máximo das 3) } Três chamadas que somariam 3000ms sequencialmente executam em apenas ~1200ms em paralelo.\nErros Comuns Usar runBlocking em código de produção: runBlocking bloqueia a thread atual. Em Android, usá-lo na Main thread causará ANR (Application Not Responding). Use viewModelScope.launch ou lifecycleScope.launch em vez disso.\nEsquecer de tratar CancellationException: se você captura Exception genérica dentro de uma coroutine, pode acidentalmente engolir o CancellationException e impedir o cancelamento. Sempre relance CancellationException ou capture exceções mais específicas.\nCriar coroutines com GlobalScope: GlobalScope.launch cria coroutines sem structured concurrency — elas não são canceladas quando a tela muda ou o componente é destruído. Isso causa memory leaks. Sempre use scopes apropriados.\nNão usar o dispatcher correto: executar operações de I/O no Dispatchers.Main vai congelar a UI. Sempre use Dispatchers.IO para rede e disco, e Dispatchers.Default para computação pesada.\nConfundir launch com async: use launch quando não precisa de retorno (fire-and-forget) e async quando precisa de um resultado. Usar async sem nunca chamar await() pode mascarar exceções.\nConclusão e Próximos Passos Coroutines são a forma idiomática de fazer programação assíncrona em Kotlin. Neste tutorial, você aprendeu suspend functions, launch e async/await, runBlocking, dispatchers, structured concurrency e cancelamento. Esses fundamentos são suficientes para começar a usar coroutines em projetos reais.\nPara avançar no tema, explore:\nFlow para streams de dados assíncronos Channels para comunicação entre coroutines Sealed Classes para modelar estados de resultado de operações assíncronas Lambdas que são a base dos coroutine builders A documentação oficial do Kotlin sobre coroutines é excelente e cobre cenários avançados como supervisão, exception handling e testing. Pratique refatorando callbacks existentes para coroutines e sinta a diferença na legibilidade do código. Para comparar modelos de concorrência, veja como Go usa goroutines e channels para concorrência e como Rust implementa async/await com o runtime Tokio.\n","permalink":"https://kotlin.dev.br/tutoriais/coroutines-tutorial-basico/","summary":"\u003cp\u003eNeste tutorial, você vai aprender os fundamentos de \u003cstrong\u003eCoroutines em Kotlin\u003c/strong\u003e — o mecanismo oficial da linguagem para programação assíncrona e concorrente. Coroutines permitem escrever código assíncrono de forma sequencial e legível, sem callbacks aninhados ou complexidade desnecessária. Ao final, você vai dominar suspend functions, \u003ccode\u003elaunch\u003c/code\u003e, \u003ccode\u003easync\u003c/code\u003e/\u003ccode\u003eawait\u003c/code\u003e, dispatchers, structured concurrency e os conceitos básicos de cancelamento.\u003c/p\u003e\n\u003ch2 id=\"o-que-são-coroutines\"\u003eO que São Coroutines?\u003c/h2\u003e\n\u003cp\u003eUma \u003ca href=\"/glossario/coroutine/\"\u003ecoroutine\u003c/a\u003e é uma instância de computação suspensível. Diferente de threads do sistema operacional, coroutines são extremamente leves — você pode criar milhares delas sem problemas de performance. Enquanto uma thread bloqueada consome recursos do sistema, uma coroutine suspensa libera a thread para fazer outro trabalho.\u003c/p\u003e","title":"Coroutines em Kotlin Tutorial Básico em Português — Passo a Passo | Kotlin Brasil"},{"content":"O desenvolvimento Android com Kotlin se tornou o padrão da industria desde que o Google anunciou Kotlin como a linguagem oficial para Android em 2019. Hoje, mais de 70% dos 1000 principais apps da Play Store utilizam Kotlin, é a tendencia só cresce. Se você esta comecando no mundo Android ou migrando de Java, este guia vai te acompanhar desde os conceitos fundamentais até tecnicas avançadas que profissionais utilizam no dia a dia. Vamos explorar a configuração do ambiente, criação de projetos, componentes essenciais e padrões que fazem a diferenca em aplicações reais.\nConfigurando o Ambiente de Desenvolvimento O primeiro passo para desenvolver Android com Kotlin e configurar o Android Studio, a IDE oficial do Google baseada no IntelliJ IDEA. Apos a instalacao, o Android Studio já vem com suporte nativo a Kotlin, sem necessidade de plugins adicionais.\nAo criar um novo projeto, selecione Kotlin como linguagem padrão. O arquivo build.gradle.kts do modulo app tera a seguinte configuração básica:\nplugins { id(\u0026#34;com.android.application\u0026#34;) id(\u0026#34;org.jetbrains.kotlin.android\u0026#34;) } android { namespace = \u0026#34;com.exemplo.meuapp\u0026#34; compileSdk = 34 defaultConfig { applicationId = \u0026#34;com.exemplo.meuapp\u0026#34; minSdk = 24 targetSdk = 34 versionCode = 1 versionName = \u0026#34;1.0\u0026#34; } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = \u0026#34;17\u0026#34; } } dependencies { implementation(\u0026#34;androidx.core:core-ktx:1.12.0\u0026#34;) implementation(\u0026#34;androidx.appcompat:appcompat:1.6.1\u0026#34;) implementation(\u0026#34;com.google.android.material:material:1.11.0\u0026#34;) implementation(\u0026#34;androidx.constraintlayout:constraintlayout:2.1.4\u0026#34;) } Activities e o Ciclo de Vida A Activity e o componente fundamental de uma aplicação Android. Ela representa uma tela com interface grafica. Em Kotlin, a sintaxe para criar uma Activity e muito mais concisa do que em Java:\nclass MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.botaoSaudacao.setOnClickListener { val nome = binding.campoNome.text.toString() binding.textoSaudacao.text = \u0026#34;Ola, $nome! Bem-vindo ao app.\u0026#34; } } override fun onResume() { super.onResume() // Logica executada quando a Activity volta ao primeiro plano } override fun onPause() { super.onPause() // Salvar estado temporario aqui } } O ciclo de vida segue a sequência: onCreate -\u0026gt; onStart -\u0026gt; onResume -\u0026gt; onPause -\u0026gt; onStop -\u0026gt; onDestroy. Compreender esse fluxo e essencial para evitar vazamentos de memória e comportamentos inesperados.\nView Binding e Data Binding O View Binding elimina a necessidade de findViewById, tornando o código mais seguro e legivel. Para ativa-lo, adicione no build.gradle.kts:\nandroid { buildFeatures { viewBinding = true } } Com isso, cada arquivo XML de layout gera automaticamente uma classe de binding. O acesso aos elementos da interface se torna direto e type-safe, evitando erros de cast e referências nulas.\nO Data Binding vai além, permitindo vincular dados diretamente no XML do layout, reduzindo código boilerplate na Activity ou Fragment.\nFragments e Navegação Fragments representam partes reutilizaveis de uma interface. Com o Navigation Component do Jetpack, a navegação entre fragments se torna declarativa e mais fácil de manter:\nclass ListaFragment : Fragment(R.layout.fragment_lista) { private var _binding: FragmentListaBinding? = null private val binding get() = _binding!! override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) _binding = FragmentListaBinding.bind(view) binding.botaoDetalhes.setOnClickListener { val acao = ListaFragmentDirections .actionListaParaDetalhes(itemId = 42) findNavController().navigate(acao) } } override fun onDestroyView() { super.onDestroyView() _binding = null } } A prática de anular o binding em onDestroyView e fundamental para evitar vazamentos de memória em Fragments.\nRecyclerView com Kotlin O RecyclerView e o componente padrão para exibir listas. Com Kotlin, o Adapter fica muito mais limpo:\nclass ProdutoAdapter( private val produtos: List\u0026lt;Produto\u0026gt;, private val onItemClick: (Produto) -\u0026gt; Unit ) : RecyclerView.Adapter\u0026lt;ProdutoAdapter.ViewHolder\u0026gt;() { inner class ViewHolder( private val binding: ItemProdutoBinding ) : RecyclerView.ViewHolder(binding.root) { fun bind(produto: Produto) { binding.nomeProduto.text = produto.nome binding.precoProduto.text = \u0026#34;R$ ${produto.preco}\u0026#34; binding.root.setOnClickListener { onItemClick(produto) } } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = ItemProdutoBinding.inflate( LayoutInflater.from(parent.context), parent, false ) return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.bind(produtos[position]) } override fun getItemCount() = produtos.size } Note o uso de lambdas para o callback de clique, um padrão muito idiomatico em Kotlin.\nViewModel e LiveData O ViewModel sobrevive a mudancas de configuração como rotação de tela. Combinado com LiveData, permite uma arquitetura reativa:\nclass ProdutoViewModel( private val repository: ProdutoRepository ) : ViewModel() { private val _produtos = MutableLiveData\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt;() val produtos: LiveData\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt; = _produtos private val _carregando = MutableLiveData\u0026lt;Boolean\u0026gt;() val carregando: LiveData\u0026lt;Boolean\u0026gt; = _carregando fun carregarProdutos() { viewModelScope.launch { _carregando.value = true try { val resultado = repository.buscarProdutos() _produtos.value = resultado } catch (e: Exception) { // Tratar erro } finally { _carregando.value = false } } } } O viewModelScope garante que as coroutines sejam canceladas automaticamente quando o ViewModel e destruído.\nRoom Database para Persistencia Local O Room e a biblioteca oficial do Jetpack para persistencia local com SQLite:\n@Entity(tableName = \u0026#34;produtos\u0026#34;) data class ProdutoEntity( @PrimaryKey(autoGenerate = true) val id: Long = 0, @ColumnInfo(name = \u0026#34;nome\u0026#34;) val nome: String, @ColumnInfo(name = \u0026#34;preco\u0026#34;) val preco: Double ) @Dao interface ProdutoDao { @Query(\u0026#34;SELECT * FROM produtos ORDER BY nome\u0026#34;) fun listarTodos(): Flow\u0026lt;List\u0026lt;ProdutoEntity\u0026gt;\u0026gt; @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun inserir(produto: ProdutoEntity) @Delete suspend fun remover(produto: ProdutoEntity) } @Database(entities = [ProdutoEntity::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun produtoDao(): ProdutoDao } O uso de Flow permite observar mudancas no banco de dados em tempo real.\nBoas Práticas no Desenvolvimento Android com Kotlin Seguir boas práticas eleva a qualidade do seu código é fácilita a manutenção a longo prazo:\nUtilize extension functions para adicionar funcionalidades a classes do Android sem heranca. Prefira imutabilidade com val em vez de var sempre que possível. Use sealed classes para representar estados da UI de forma segura. Aplique o padrão Repository para abstrair fontes de dados. Concentre chamadas REST em Retrofit com Kotlin e mantenha cache local com Room quando a tela precisar abrir em rede ruim. Utilize Kotlin Coroutines em vez de AsyncTask ou callbacks aninhados. Mantenha Activities e Fragments enxutos, delegando lógica ao ViewModel. Implemente tratamento de erros robusto em chamadas de rede. sealed class UiState\u0026lt;out T\u0026gt; { object Loading : UiState\u0026lt;Nothing\u0026gt;() data class Success\u0026lt;T\u0026gt;(val data: T) : UiState\u0026lt;T\u0026gt;() data class Error(val mensagem: String) : UiState\u0026lt;Nothing\u0026gt;() } Erros Comuns e Armadilhas Desenvolvedores iniciantes e até experientes cometem alguns erros recorrentes no Android com Kotlin:\nVazamento de memória em Fragments: esquecer de anular o binding em onDestroyView causa leaks. Sempre limpe referências. Bloquear a thread principal: executar operações de rede ou banco de dados na main thread causa ANR (Application Not Responding). Use coroutines com Dispatchers.IO. Ignorar o ciclo de vida: não cancelar observers ou jobs quando a Activity e destruida leva a crashes e comportamentos erraticos. Uso excessivo de lateinit: se a variavel pode ser nula, use nullable com operador ?. em vez de lateinit, que lanca exceção se acessada antes da inicialização. Nao tratar rotação de tela: dados perdidos na rotação são um problema clássico. O ViewModel resolve isso naturalmente. Hardcoded strings: sempre use recursos de string (strings.xml) para facilitar internacionalizacao e manutenção. Conclusão e Próximos Passos O desenvolvimento Android com Kotlin oferece uma experiência produtiva e moderna. Com os fundamentos cobertos neste guia \u0026ndash; Activities, Fragments, ViewModels, Room e boas práticas \u0026ndash; você tem uma base solida para construir aplicações robustas.\nComo próximos passos, recomendamos explorar o Jetpack Compose para interfaces declarativas, aprofundar-se em Coroutines para programação assíncrona avançada e estudar arquiteturas como MVVM e Clean Architecture para projetos maiores. Cada um desses topicos possui um guia dedicado aqui no Kotlin Brasil. Continue praticando e construindo projetos reais, pois a experiência prática e o melhor caminho para a maestria no desenvolvimento Android.\n","permalink":"https://kotlin.dev.br/guias/guia-kotlin-android-desenvolvimento/","summary":"\u003cp\u003eO desenvolvimento Android com Kotlin se tornou o padrão da industria desde que o Google anunciou Kotlin como a linguagem oficial para Android em 2019. Hoje, mais de 70% dos 1000 principais apps da Play Store utilizam Kotlin, é a tendencia só cresce. Se você esta comecando no mundo Android ou migrando de Java, este guia vai te acompanhar desde os conceitos fundamentais até tecnicas avançadas que profissionais utilizam no dia a dia. Vamos explorar a configuração do ambiente, criação de projetos, componentes essenciais e padrões que fazem a diferenca em aplicações reais.\u003c/p\u003e","title":"Desenvolvimento Android com Kotlin: Guia Completo em Português | Kotlin Brasil"},{"content":"Neste tutorial, você vai aprender a trabalhar com todas as estruturas de repetição disponíveis em Kotlin: for, while e do-while. Vamos explorar ranges, iteração sobre coleções, controle de fluxo com break e continue, e padrões idiomáticos que tornam seus loops mais expressivos e seguros.\nO Loop For em Kotlin O loop for em Kotlin é diferente do for tradicional de Java ou C. Ele não usa a sintaxe de três partes (inicialização; condição; incremento). Em vez disso, Kotlin usa uma abordagem mais moderna baseada em iteradores, semelhante ao for-each de outras linguagens.\nA forma mais comum do for em Kotlin itera sobre um range (intervalo) ou sobre uma coleção. Essa abordagem é mais segura porque elimina erros comuns como off-by-one e índices fora dos limites.\nfun main() { // For com range (intervalo inclusivo) println(\u0026#34;=== Contando de 1 a 10 ===\u0026#34;) for (i in 1..10) { print(\u0026#34;$i \u0026#34;) } println() // For com range exclusivo (until / ..\u0026lt;) println(\u0026#34;\\n=== Índices de 0 a 4 (exclusivo no final) ===\u0026#34;) for (i in 0 until 5) { print(\u0026#34;$i \u0026#34;) } println() // For com passo (step) println(\u0026#34;\\n=== Números pares de 2 a 20 ===\u0026#34;) for (i in 2..20 step 2) { print(\u0026#34;$i \u0026#34;) } println() // For decrescente (downTo) println(\u0026#34;\\n=== Contagem regressiva ===\u0026#34;) for (i in 10 downTo 1) { print(\u0026#34;$i \u0026#34;) } println(\u0026#34;\\nFogo!\u0026#34;) // For decrescente com passo println(\u0026#34;\\n=== De 100 a 0, de 10 em 10 ===\u0026#34;) for (i in 100 downTo 0 step 10) { print(\u0026#34;$i \u0026#34;) } println() } Os ranges são uma funcionalidade poderosa do Kotlin. O operador .. cria um range inclusivo (ambos os limites são incluídos), enquanto until ou ..\u0026lt; cria um range exclusivo no final (útil para trabalhar com índices de arrays). O downTo permite iteração decrescente, e step define o incremento entre os valores.\nIterando sobre Coleções Na prática do dia a dia, você vai usar for mais frequentemente para iterar sobre listas, arrays e outras coleções do que sobre ranges numéricos. Kotlin oferece várias formas elegantes de fazer isso.\nfun main() { val frutas = listOf(\u0026#34;Maçã\u0026#34;, \u0026#34;Banana\u0026#34;, \u0026#34;Laranja\u0026#34;, \u0026#34;Manga\u0026#34;, \u0026#34;Uva\u0026#34;) // Iteração simples sobre lista println(\u0026#34;=== Frutas ===\u0026#34;) for (fruta in frutas) { println(\u0026#34; - $fruta\u0026#34;) } // Iteração com índice usando withIndex() println(\u0026#34;\\n=== Frutas com índice ===\u0026#34;) for ((indice, fruta) in frutas.withIndex()) { println(\u0026#34; $indice: $fruta\u0026#34;) } // Iteração sobre Map (chave-valor) val capitais = mapOf( \u0026#34;SP\u0026#34; to \u0026#34;São Paulo\u0026#34;, \u0026#34;RJ\u0026#34; to \u0026#34;Rio de Janeiro\u0026#34;, \u0026#34;MG\u0026#34; to \u0026#34;Belo Horizonte\u0026#34;, \u0026#34;BA\u0026#34; to \u0026#34;Salvador\u0026#34;, \u0026#34;RS\u0026#34; to \u0026#34;Porto Alegre\u0026#34; ) println(\u0026#34;\\n=== Capitais ===\u0026#34;) for ((sigla, capital) in capitais) { println(\u0026#34; $sigla -\u0026gt; $capital\u0026#34;) } // Iteração sobre String (caracteres) val palavra = \u0026#34;KOTLIN\u0026#34; println(\u0026#34;\\n=== Letras de \u0026#39;$palavra\u0026#39; ===\u0026#34;) for (letra in palavra) { print(\u0026#34;[$letra] \u0026#34;) } println() // Iteração sobre array com índices val numeros = intArrayOf(10, 20, 30, 40, 50) println(\u0026#34;\\n=== Array com indices ===\u0026#34;) for (i in numeros.indices) { println(\u0026#34; numeros[$i] = ${numeros[i]}\u0026#34;) } } A desestruturação com (indice, valor) no withIndex() e (chave, valor) nos maps é uma sintaxe muito prática que torna o código mais legível. Ela funciona com qualquer classe que declare os operadores component1(), component2(), etc., como as data classes.\nWhile e Do-While Os loops while e do-while funcionam de maneira semelhante a outras linguagens. Use while quando não souber antecipadamente quantas iterações serão necessárias e do-while quando precisar garantir que o bloco execute pelo menos uma vez.\nfun main() { // While basico println(\u0026#34;=== Sequência de Fibonacci até 100 ===\u0026#34;) var a = 0 var b = 1 while (a \u0026lt;= 100) { print(\u0026#34;$a \u0026#34;) val temp = a + b a = b b = temp } println() // Do-while — executa pelo menos uma vez println(\u0026#34;\\n=== Adivinhe o numero (simulação) ===\u0026#34;) val numeroSecreto = 7 var tentativa = 0 var palpite: Int do { tentativa++ palpite = tentativa * 2 + 1 // simulando palpites println(\u0026#34;Tentativa $tentativa: palpite = $palpite\u0026#34;) } while (palpite != numeroSecreto) println(\u0026#34;Acertou em $tentativa tentativas!\u0026#34;) // While para processar dados println(\u0026#34;\\n=== Processando fila ===\u0026#34;) val fila = mutableListOf(\u0026#34;Pedido-001\u0026#34;, \u0026#34;Pedido-002\u0026#34;, \u0026#34;Pedido-003\u0026#34;, \u0026#34;Pedido-004\u0026#34;) while (fila.isNotEmpty()) { val pedido = fila.removeFirst() println(\u0026#34;Processando: $pedido (restam ${fila.size})\u0026#34;) } println(\u0026#34;Fila processada!\u0026#34;) } A diferença fundamental entre while e do-while é que o do-while verifica a condição após executar o bloco, garantindo pelo menos uma execução. Isso é útil em cenários como válidação de entrada do usuário, onde você precisa pedir o valor antes de verificar se ele é válido.\nControle de Fluxo: break, continue e Labels Kotlin oferece as instruções break e continue para controlar o fluxo dentro de loops. Além disso, o sistema de labels permite direcionar essas instruções para loops específicos em estruturas aninhadas, evitando ambiguidade.\nfun main() { // break — interrompe o loop println(\u0026#34;=== Procurando primeiro múltiplo de 7 ===\u0026#34;) for (i in 1..100) { if (i % 7 == 0) { println(\u0026#34;Encontrado: $i\u0026#34;) break } } // continue — pula para próxima iteração println(\u0026#34;\\n=== Números nao divisíveis por 3 (de 1 a 15) ===\u0026#34;) for (i in 1..15) { if (i % 3 == 0) continue print(\u0026#34;$i \u0026#34;) } println() // Labels para loops aninhados println(\u0026#34;\\n=== Busca em matriz com label ===\u0026#34;) val matriz = arrayOf( intArrayOf(1, 2, 3), intArrayOf(4, 5, 6), intArrayOf(7, 8, 9) ) val alvo = 5 busca@ for (i in matriz.indices) { for (j in matriz[i].indices) { if (matriz[i][j] == alvo) { println(\u0026#34;Valor $alvo encontrado na posição [$i][$j]\u0026#34;) break@busca // sai de AMBOS os loops } } } // continue com label println(\u0026#34;\\n=== Pares de numeros (sem repetição do primeiro) ===\u0026#34;) externo@ for (i in 1..3) { for (j in 1..3) { if (i == j) continue@externo println(\u0026#34; ($i, $j)\u0026#34;) } } } Os labels são nomeados com o sufixo @ e podem ser aplicados a qualquer loop. break@label interrompe o loop marcado, enquanto continue@label pula para a próxima iteração do loop marcado. Use labels com moderação — código com muitos labels pode se tornar difícil de ler. Considere extrair a lógica para uma função separada como alternativa.\nAlternativas Funcionais aos Loops Kotlin oferece uma rica biblioteca de funções de alta ordem que frequentemente substituem loops tradicionais com código mais expressivo e conciso. Embora loops explícitos sejam perfeitamente válidos, conhecer essas alternativas é importante para escrever código idiomático.\nAs funções forEach, map, filter, reduce e muitas outras estão disponíveis em todas as coleções do Kotlin. Elas serão exploradas em detalhes nos tutoriais sobre Listas, Sets e Maps e Lambdas e Higher-Order Functions, mas aqui vai uma amostra para que você saiba que essas alternativas existem.\nDicas e Erros Comuns Ao trabalhar com loops em Kotlin, esteja atento a estes pontos:\nUsar range inclusivo quando deveria ser exclusivo: for (i in 0..lista.size) vai causar IndexOutOfBoundsException porque inclui lista.size. Use 0 until lista.size ou melhor ainda, lista.indices.\nTentar modificar uma coleção durante iteração com for: isso lança ConcurrentModificationException. Use iterator.remove() ou crie uma nova coleção filtrada.\nLoops infinitos acidentais com while: sempre garanta que a condição do while vai eventualmente se tornar falsa. Um while (true) sem break adequado trava o programa.\nNão usar indices ou withIndex(): em vez de for (i in 0 until lista.size), prefira for (i in lista.indices) ou for ((i, v) in lista.withIndex()). É mais idiomático e seguro.\nAbusar de break e continue com labels: se o código tem muitos labels, provavelmente deveria ser refatorado. Extraia a lógica para funções menores e mais claras.\nUsar loops onde funções de coleção seriam mais claras: para transformações simples como filtrar ou mapear, as extension functions de coleção geralmente produzem código mais legível que loops manuais.\nConclusão e Próximos Passos Neste tutorial, você dominou todas as estruturas de repetição do Kotlin. O loop for com ranges e coleções, while e do-while para iterações condicionais, e os mecanismos de controle de fluxo com break, continue e labels. Esses são ferramentas essenciais que você vai usar em praticamente todo programa que escrever.\nPara continuar evoluindo, siga para estes tutoriais:\nFunções em Kotlin — aprenda a criar funções reutilizáveis Listas, Sets e Maps — domine as coleções e suas operações Lambdas e Higher-Order Functions — descubra alternativas funcionais aos loops Pratique criando programas que combinem loops com as estruturas condicionais que aprendemos anteriormente. Bons exercícios incluem tabuada, sequência de Fibonacci, números primos e ordenação de listas. Até o próximo tutorial!\n","permalink":"https://kotlin.dev.br/tutoriais/loops-kotlin/","summary":"\u003cp\u003eNeste tutorial, você vai aprender a trabalhar com todas as estruturas de repetição disponíveis em Kotlin: \u003ccode\u003efor\u003c/code\u003e, \u003ccode\u003ewhile\u003c/code\u003e e \u003ccode\u003edo-while\u003c/code\u003e. Vamos explorar ranges, iteração sobre coleções, controle de fluxo com \u003ccode\u003ebreak\u003c/code\u003e e \u003ccode\u003econtinue\u003c/code\u003e, e padrões idiomáticos que tornam seus loops mais expressivos e seguros.\u003c/p\u003e\n\u003ch2 id=\"o-loop-for-em-kotlin\"\u003eO Loop For em Kotlin\u003c/h2\u003e\n\u003cp\u003eO loop \u003ccode\u003efor\u003c/code\u003e em Kotlin é diferente do \u003ccode\u003efor\u003c/code\u003e tradicional de Java ou C. Ele não usa a sintaxe de três partes (\u003ccode\u003einicialização; condição; incremento\u003c/code\u003e). Em vez disso, Kotlin usa uma abordagem mais moderna baseada em iteradores, semelhante ao \u003ccode\u003efor-each\u003c/code\u003e de outras linguagens.\u003c/p\u003e","title":"Loops em Kotlin: For, While e Do-While Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Kotlin e Dart são duas linguagens que frequentemente aparecem lado a lado em discussoes sobre desenvolvimento mobile. Kotlin é a linguagem oficial do Android, enquanto Dart é a linguagem do Flutter. Mas as diferenças vao muito além do framework que cada uma alimenta. Vamos explorar em detalhes.\nAs Linguagens em Contexto Dart foi criada pelo Google em 2011 com o objetivo original de substituir o JavaScript nos navegadores. Esse plano não deu certo, é a linguagem ficou relativamente esquecida até o lancamento do Flutter em 2017, que deu nova vida ao Dart.\nKotlin foi criada pela JetBrains e lancada em 2016. Desde entao, cresceu exponencialmente, tornando-se a linguagem oficial do Android em 2019 e expandindo para backend, multiplatform e web.\nComparação de Sintaxe Declaracao de Classes // Kotlin - Data class concisa data class Produto( val id: String, val nome: String, val preco: Double, val estoque: Int = 0 // Valor padrao ) // Uso val produto = Produto( id = \u0026#34;123\u0026#34;, nome = \u0026#34;Teclado Mecanico\u0026#34;, preco = 299.90 ) val atualizado = produto.copy(preco = 249.90) Em Dart, você precisa declarar muito mais código para obter a mesma funcionalidade. Packages como freezed ajudam, mas adicionam complexidade com code generation.\nNull Safety Ambas as linguagens tem null safety, mas a implementação do Kotlin e mais madura e elegante:\n// Kotlin - Null safety integrada fun buscarPreco(produtoId: String?): Double { // Smart cast apos verificacao if (produtoId == null) return 0.0 // Aqui, produtoId e automaticamente String (nao nullable) val produto = repository.findById(produtoId) // Safe call + Elvis operator return produto?.preco ?: 0.0 } // Scope functions para trabalhar com nullables fun exibirProduto(produto: Produto?) { produto?.let { p -\u0026gt; println(\u0026#34;Nome: ${p.nome}\u0026#34;) println(\u0026#34;Preco: R$ ${p.preco}\u0026#34;) } ?: println(\u0026#34;Produto nao encontrado\u0026#34;) } Dart adicionou null safety na versão 2.12, inspirado justamente no Kotlin. A implementação e boa, mas falta o operador Elvis completo e as scope functions que tornam o código Kotlin tao expressivo.\nTratamento de Erros // Kotlin - Result type para tratamento funcional de erros sealed class AppError { data class Network(val message: String) : AppError() data class Validation(val campo: String, val erro: String) : AppError() data class NotFound(val recurso: String) : AppError() } fun buscarUsuario(id: String): Result\u0026lt;Usuario\u0026gt; { return runCatching { val response = api.getUsuario(id) if (response.isSuccessful) { response.body() ?: throw NotFoundException(\u0026#34;Usuario $id\u0026#34;) } else { throw NetworkException(response.message()) } } } // Uso elegante buscarUsuario(\u0026#34;123\u0026#34;) .onSuccess { usuario -\u0026gt; exibir(usuario) } .onFailure { erro -\u0026gt; mostrarErro(erro) } Kotlin oferece sealed classes, Result types e extension functions que juntos criam um sistema de tratamento de erros muito mais expressivo e seguro que o try-catch tradicional do Dart.\nConcorrência e Assincronia Esta e uma das maiores diferenças entre as duas linguagens.\n// Kotlin Coroutines - Concorrência estruturada class SyncService( private val localDb: LocalDatabase, private val remoteApi: RemoteApi ) { suspend fun sincronizar() = coroutineScope { // Buscar dados em paralelo val usuarios = async(Dispatchers.IO) { remoteApi.getUsuarios() } val produtos = async(Dispatchers.IO) { remoteApi.getProdutos() } val configurações = async(Dispatchers.IO) { remoteApi.getConfiguracoes() } // Aguardar todos e salvar localmente localDb.salvarUsuarios(usuarios.await()) localDb.salvarProdutos(produtos.await()) localDb.salvarConfiguracoes(configurações.await()) } } Dart tem async/await que funciona bem para operações sequenciais, mas o modelo de concorrência e limitado. Dart e single-threaded com event loop (similar a JavaScript). Para trabalho pesado, você precisa de Isolates, que são mais complicados de usar que coroutines.\nKotlin Coroutines oferecem:\nStructured concurrency: Coroutines filhas são automaticamente canceladas se a pai falhar Dispatchers: Controle fino sobre em qual thread o código executa Flow: Streams reativos integrados a linguagem Channels: Comunicação entre coroutines // Kotlin Flow - Reatividade integrada fun observarProdutos(categoriaId: String): Flow\u0026lt;List\u0026lt;Produto\u0026gt;\u0026gt; { return database.observarProdutosPorCategoria(categoriaId) .map { entidades -\u0026gt; entidades.map { it.toProduto() } } .catch { e -\u0026gt; logger.error(\u0026#34;Erro ao observar produtos\u0026#34;, e) emit(emptyList()) } .flowOn(Dispatchers.IO) } Ecossistema e Bibliotecas Kotlin O ecossistema Kotlin e vastissimo gracas a interoperabilidade com Java:\n// Kotlin pode usar QUALQUER biblioteca Java // Alem das bibliotecas nativas Kotlin: // kotlinx.serialization - Serializacao nativa @Serializable data class ApiResponse\u0026lt;T\u0026gt;( val data: T, val status: String, @SerialName(\u0026#34;total_count\u0026#34;) val totalCount: Int ) // Ktor Client - HTTP client nativo Kotlin val client = HttpClient(CIO) { install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true prettyPrint = true }) } install(Logging) { level = LogLevel.INFO } } Kotlin tem acesso a milhoes de bibliotecas Java no Maven Central, além de bibliotecas nativas Kotlin que crescem a cada dia. Dart tem o pub.dev, que e muito menor em comparação.\nVersatilidade Kotlin pode ser usada para:\nAndroid nativo (Jetpack Compose) iOS (Kotlin Multiplatform) Backend (Spring Boot, Ktor) Desktop (Compose Multiplatform) Web (Kotlin/JS, Compose for Web) Scripts e automação Dart e quase exclusivamente usado para Flutter. Fora do Flutter, o ecossistema Dart e muito limitado. Existe Dart para server-side, mas a adoção e minima comparada a Kotlin com Spring Boot ou Ktor.\nPerformance Kotlin na JVM se beneficia de decadas de otimização. O JIT compiler da JVM transforma bytecode em código nativo otimizado para o hardware específico onde esta rodando. Isso significa que aplicações Kotlin ficam mais rápidas com o tempo de execução.\nDart compila para código nativo em mobile (AOT compilation), o que é bom para Flutter. Mas para server-side, Dart não compete com a JVM em throughput e latencia.\nPara desenvolvimento Android especificamente, Kotlin nativo tem acesso direto as APIs do sistema, sem nenhuma camada intermediaria. Flutter com Dart precisa de platform channels para acessar funcionalidades nativas, adicionando overhead e complexidade.\nTooling e IDE Kotlin foi criada pela mesma empresa que criou o IntelliJ IDEA. O suporte de IDE e excepcional:\nRefactoring avançado e confiavel Code analysis em tempo real Debugger integrado com visualização de coroutines Profiling de memória e CPU Preview de Compose em tempo real Dart tem suporte razoavel no VS Code e Android Studio, mas o tooling não chega perto do que Kotlin oferece. O hot reload do Flutter e impressionante para UI, mas o ecossistema de ferramentas como um todo e menos maduro.\nComunidade e Futuro A comunidade Kotlin e grande e diversa, abrangendo desenvolvedores Android, backend, multiplatform e mais. A JetBrains e o Google investem fortemente na linguagem, e o ritmo de evolução e constante.\nA comunidade Dart depende quase inteiramente do Flutter. Se o Flutter perder relevancia, Dart provavelmente perde junto. Kotlin, por outro lado, tem múltiplos pilares de sustentacao e não depende de nenhum framework específico.\nConclusão Dart e uma linguagem competente que serve bem ao proposito do Flutter. Mas quando comparada diretamente ao Kotlin, fica claro que Kotlin e uma linguagem mais poderosa, mais versatil e com um ecossistema incomparavelmente maior.\nSe você esta escolhendo uma linguagem para investir na sua carreira, Kotlin oferece muito mais caminhos: mobile, backend, multiplatform e além. Dart te prende ao ecossistema Flutter, que por mais popular que seja, e apenas uma fracao do que Kotlin pode oferecer.\nPara desenvolvedores brasileiros, Kotlin abre portas em bancos, fintechs, grandes empresas de tecnologia e startups, tanto para mobile quanto para backend. Se o backend é o seu foco além do mobile, vale conhecer também Go e Python como linguagens complementares. E uma aposta segura e com retorno garantido.\n","permalink":"https://kotlin.dev.br/blog/kotlin-vs-dart/","summary":"\u003cp\u003eKotlin e Dart são duas linguagens que frequentemente aparecem lado a lado em discussoes sobre desenvolvimento mobile. Kotlin é a linguagem oficial do Android, enquanto Dart é a linguagem do Flutter. Mas as diferenças vao muito além do framework que cada uma alimenta. Vamos explorar em detalhes.\u003c/p\u003e\n\u003ch2 id=\"as-linguagens-em-contexto\"\u003eAs Linguagens em Contexto\u003c/h2\u003e\n\u003cp\u003eDart foi criada pelo Google em 2011 com o objetivo original de substituir o JavaScript nos navegadores. Esse plano não deu certo, é a linguagem ficou relativamente esquecida até o lancamento do Flutter em 2017, que deu nova vida ao Dart.\u003c/p\u003e","title":"Kotlin vs Dart: Qual Linguagem Escolher para Mobile? | Kotlin Brasil"},{"content":"Neste tutorial, você vai aprender tudo sobre Generics em Kotlin — um recurso fundamental para escrever código reutilizável e type-safe. Generics permitem criar classes, interfaces e funções que operam com diferentes tipos sem sacrificar a segurança de tipos do compilador. Ao final, você vai dominar type parameters, constraints, variance com in/out, star projection e reified type parameters.\nO que São Generics? Generics permitem que você escreva código que funciona com qualquer tipo, enquanto ainda mantém a verificação de tipos em tempo de compilação. Sem generics, você teria que usar Any e fazer casts manuais, perdendo a segurança de tipos.\nVocê já usa generics diariamente, mesmo sem perceber. Toda vez que declara uma List\u0026lt;String\u0026gt;, Map\u0026lt;String, Int\u0026gt; ou MutableList\u0026lt;Usuario\u0026gt;, está usando generics.\nType Parameters Básicos A sintaxe básica de generics usa colchetes angulares \u0026lt;T\u0026gt;, onde T é o type parameter — um \u0026ldquo;placeholder\u0026rdquo; para o tipo real que será usado:\n// Classe genérica class Caixa\u0026lt;T\u0026gt;(val conteudo: T) { fun abrir(): T = conteudo fun transformar(bloco: (T) -\u0026gt; String): String { return bloco(conteudo) } } fun main() { val caixaTexto = Caixa(\u0026#34;Kotlin Brasil\u0026#34;) println(caixaTexto.abrir()) // Kotlin Brasil val caixaNumero = Caixa(42) println(caixaNumero.abrir()) // 42 // O tipo é inferido automaticamente val caixaLista = Caixa(listOf(1, 2, 3)) println(caixaLista.abrir()) // [1, 2, 3] // Transformando o conteúdo println(caixaNumero.transformar { \u0026#34;O numero é $it\u0026#34; }) } Note que o compilador infere o tipo genérico automaticamente na maioria dos casos. Você não precisa escrever Caixa\u0026lt;String\u0026gt;(\u0026quot;Kotlin Brasil\u0026quot;) — o compilador deduz String a partir do argumento.\nFunções Genéricas Funções também podem ser genéricas, independentemente de estarem dentro de uma classe genérica ou não:\nfun \u0026lt;T\u0026gt; primeiroOuNull(lista: List\u0026lt;T\u0026gt;): T? { return if (lista.isNotEmpty()) lista[0] else null } fun \u0026lt;T\u0026gt; List\u0026lt;T\u0026gt;.trocar(indice1: Int, indice2: Int): List\u0026lt;T\u0026gt; { val resultado = this.toMutableList() val temp = resultado[indice1] resultado[indice1] = resultado[indice2] resultado[indice2] = temp return resultado } fun \u0026lt;K, V\u0026gt; mapearPares(pares: List\u0026lt;Pair\u0026lt;K, V\u0026gt;\u0026gt;): Map\u0026lt;K, V\u0026gt; { return pares.toMap() } fun main() { println(primeiroOuNull(listOf(\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;))) // a println(primeiroOuNull(emptyList\u0026lt;Int\u0026gt;())) // null val numeros = listOf(10, 20, 30, 40) println(numeros.trocar(0, 3)) // [40, 20, 30, 10] val mapa = mapearPares(listOf(\u0026#34;nome\u0026#34; to \u0026#34;Ana\u0026#34;, \u0026#34;cidade\u0026#34; to \u0026#34;SP\u0026#34;)) println(mapa) // {nome=Ana, cidade=SP} } Constraints (Upper Bounds) Às vezes você quer restringir o tipo genérico para aceitar apenas subtipos de uma determinada classe ou interface. Isso é feito com upper bounds:\n// T precisa ser Comparable fun \u0026lt;T : Comparable\u0026lt;T\u0026gt;\u0026gt; maximo(a: T, b: T): T { return if (a \u0026gt; b) a else b } // T precisa implementar CharSequence fun \u0026lt;T : CharSequence\u0026gt; contarCaracteres(texto: T): Int { return texto.length } fun main() { println(maximo(10, 20)) // 20 println(maximo(\u0026#34;abacaxi\u0026#34;, \u0026#34;banana\u0026#34;)) // banana println(contarCaracteres(\u0026#34;Kotlin\u0026#34;)) // 6 // Isto nao compila: // maximo(listOf(1), listOf(2)) — List nao é Comparable } Para múltiplas restrições, use a cláusula where:\nfun \u0026lt;T\u0026gt; processar(item: T) where T : Comparable\u0026lt;T\u0026gt;, T : CharSequence { println(\u0026#34;Valor: $item, Tamanho: ${item.length}\u0026#34;) // T é tanto Comparable quanto CharSequence } fun main() { processar(\u0026#34;Kotlin\u0026#34;) // String implementa ambas // processar(42) — Int nao implementa CharSequence — ERRO! } Variance: in e out Variance é um dos conceitos mais importantes (e confusos) de generics. Ela define como a relação de herança entre tipos afeta tipos genéricos.\nCovariância com out (Producer) Se Dog é subtipo de Animal, uma List\u0026lt;Dog\u0026gt; deveria ser subtipo de List\u0026lt;Animal\u0026gt;? Em Kotlin, sim — porque List é declarada com out:\n// out = covariante = o tipo só SAI (é produzido) interface Produtor\u0026lt;out T\u0026gt; { fun produzir(): T // fun consumir(item: T) — ERRO! Não pode usar T como parâmetro } class ProdutorDeString : Produtor\u0026lt;String\u0026gt; { override fun produzir(): String = \u0026#34;Hello Kotlin\u0026#34; } fun imprimirProduto(produtor: Produtor\u0026lt;Any\u0026gt;) { println(produtor.produzir()) } fun main() { val produtorString: Produtor\u0026lt;String\u0026gt; = ProdutorDeString() // Funciona! Produtor\u0026lt;String\u0026gt; é subtipo de Produtor\u0026lt;Any\u0026gt; imprimirProduto(produtorString) } Use out quando o tipo genérico é apenas produzido (retornado), nunca consumido como parâmetro.\nContravariância com in (Consumer) O oposto: se Dog é subtipo de Animal, um Comparator\u0026lt;Animal\u0026gt; pode ser usado onde se espera Comparator\u0026lt;Dog\u0026gt;:\n// in = contravariante = o tipo só ENTRA (é consumido) interface Consumidor\u0026lt;in T\u0026gt; { fun consumir(item: T) // fun produzir(): T — ERRO! Não pode retornar T } class ConsumidorDeAny : Consumidor\u0026lt;Any\u0026gt; { override fun consumir(item: Any) { println(\u0026#34;Consumindo: $item\u0026#34;) } } fun alimentar(consumidor: Consumidor\u0026lt;String\u0026gt;) { consumidor.consumir(\u0026#34;Kotlin\u0026#34;) } fun main() { val consumidorAny: Consumidor\u0026lt;Any\u0026gt; = ConsumidorDeAny() // Funciona! Consumidor\u0026lt;Any\u0026gt; é subtipo de Consumidor\u0026lt;String\u0026gt; alimentar(consumidorAny) } Resumo de Variance // Pense assim: // out T → Producer\u0026lt;out T\u0026gt; → T só aparece em posição de retorno // in T → Consumer\u0026lt;in T\u0026gt; → T só aparece em posição de parâmetro // Exemplos da stdlib: // List\u0026lt;out E\u0026gt; → só produz E (get, iterator) // Comparable\u0026lt;in T\u0026gt; → só consome T (compareTo recebe T) // MutableList\u0026lt;E\u0026gt; → invariante (produz E e consome E) Star Projection Quando você não sabe ou não se importa com o tipo genérico, use a star projection *:\nfun imprimirConteudo(lista: List\u0026lt;*\u0026gt;) { for (item in lista) { println(item) // item é do tipo Any? } } fun verificarTipo(caixa: Caixa\u0026lt;*\u0026gt;) { val conteudo = caixa.abrir() // tipo: Any? println(\u0026#34;Conteúdo: $conteudo\u0026#34;) } fun main() { imprimirConteudo(listOf(1, \u0026#34;dois\u0026#34;, 3.0, true)) val caixas: List\u0026lt;Caixa\u0026lt;*\u0026gt;\u0026gt; = listOf( Caixa(\u0026#34;texto\u0026#34;), Caixa(42), Caixa(true) ) caixas.forEach { verificarTipo(it) } } List\u0026lt;*\u0026gt; é equivalente a List\u0026lt;out Any?\u0026gt; — você pode ler itens como Any?, mas não pode adicionar itens (exceto null).\nReified Type Parameters Devido ao type erasure da JVM, informações sobre generics são apagadas em tempo de execução. Isso significa que você não pode fazer is T ou T::class normalmente. A solução é usar reified com funções inline:\ninline fun \u0026lt;reified T\u0026gt; verificarTipo(valor: Any): Boolean { return valor is T } inline fun \u0026lt;reified T\u0026gt; filtrarPorTipo(lista: List\u0026lt;Any\u0026gt;): List\u0026lt;T\u0026gt; { return lista.filterIsInstance\u0026lt;T\u0026gt;() } inline fun \u0026lt;reified T\u0026gt; nomeDoTipo(): String { return T::class.simpleName ?: \u0026#34;Desconhecido\u0026#34; } fun main() { println(verificarTipo\u0026lt;String\u0026gt;(\u0026#34;texto\u0026#34;)) // true println(verificarTipo\u0026lt;Int\u0026gt;(\u0026#34;texto\u0026#34;)) // false val misturada = listOf(1, \u0026#34;dois\u0026#34;, 3, \u0026#34;quatro\u0026#34;, 5.0) val strings = filtrarPorTipo\u0026lt;String\u0026gt;(misturada) println(strings) // [dois, quatro] val inteiros = filtrarPorTipo\u0026lt;Int\u0026gt;(misturada) println(inteiros) // [1, 3] println(nomeDoTipo\u0026lt;String\u0026gt;()) // String println(nomeDoTipo\u0026lt;List\u0026lt;Int\u0026gt;\u0026gt;()) // List } reified só funciona com funções inline porque o compilador substitui a chamada da função pelo seu corpo, inserindo o tipo real no lugar do type parameter.\nType Erasure Na JVM, informações de tipo genérico são apagadas durante a compilação. Isso tem implicações práticas:\nfun main() { val listaStrings = listOf(\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;) val listaInts = listOf(1, 2) // Em tempo de execucao, ambas são apenas \u0026#34;List\u0026#34; // Isto nao funciona: // if (listaStrings is List\u0026lt;String\u0026gt;) — ERRO: Cannot check for instance of erased type // Mas isto funciona com star projection: if (listaStrings is List\u0026lt;*\u0026gt;) { println(\u0026#34;É uma lista!\u0026#34;) // Funciona } // Para verificar o tipo dos elementos, use reified: } // Abordagem segura com reified inline fun \u0026lt;reified T\u0026gt; List\u0026lt;*\u0026gt;.ehListaDe(): Boolean { return all { it is T } } Exemplo Prático Completo Vamos criar um repositório genérico que funciona com qualquer entidade:\ninterface Entidade { val id: Long } data class Usuario(override val id: Long, val nome: String, val email: String) : Entidade data class Produto(override val id: Long, val nome: String, val preco: Double) : Entidade class Repositorio\u0026lt;T : Entidade\u0026gt; { private val itens = mutableMapOf\u0026lt;Long, T\u0026gt;() fun salvar(item: T): T { itens[item.id] = item return item } fun buscarPorId(id: Long): T? = itens[id] fun listarTodos(): List\u0026lt;T\u0026gt; = itens.values.toList() fun remover(id: Long): Boolean = itens.remove(id) != null fun buscar(filtro: (T) -\u0026gt; Boolean): List\u0026lt;T\u0026gt; = itens.values.filter(filtro) val tamanho: Int get() = itens.size } fun main() { val usuarios = Repositorio\u0026lt;Usuario\u0026gt;() usuarios.salvar(Usuario(1, \u0026#34;Ana\u0026#34;, \u0026#34;ana@email.com\u0026#34;)) usuarios.salvar(Usuario(2, \u0026#34;Bruno\u0026#34;, \u0026#34;bruno@email.com\u0026#34;)) usuarios.salvar(Usuario(3, \u0026#34;Carla\u0026#34;, \u0026#34;carla@email.com\u0026#34;)) println(\u0026#34;Total: ${usuarios.tamanho}\u0026#34;) val encontrado = usuarios.buscarPorId(2) println(\u0026#34;Encontrado: $encontrado\u0026#34;) val comA = usuarios.buscar { it.nome.startsWith(\u0026#34;A\u0026#34;) || it.nome.startsWith(\u0026#34;a\u0026#34;) } println(\u0026#34;Nomes com A: $comA\u0026#34;) val produtos = Repositorio\u0026lt;Produto\u0026gt;() produtos.salvar(Produto(1, \u0026#34;Notebook\u0026#34;, 3500.0)) produtos.salvar(Produto(2, \u0026#34;Mouse\u0026#34;, 89.90)) val caros = produtos.buscar { it.preco \u0026gt; 100 } println(\u0026#34;Produtos caros: $caros\u0026#34;) } Erros Comuns Esquecer type erasure: tentar fazer is List\u0026lt;String\u0026gt; em tempo de execução não funciona. Use star projection (is List\u0026lt;*\u0026gt;) ou reified com funções inline.\nConfundir in e out: lembre da regra mnemônica — out = Producer (o tipo sai), in = Consumer (o tipo entra). Se errar a variance, o compilador mostrará erros confusos sobre posições ilegais.\nUsar reified sem inline: reified só funciona com funções inline. Sem inline, o tipo seria apagado e reified não teria efeito. O compilador não permitirá essa combinação inválida.\nNão definir upper bounds quando necessário: se você chama métodos específicos de um tipo dentro de uma função genérica (como compareTo), precisa declarar o bound (\u0026lt;T : Comparable\u0026lt;T\u0026gt;\u0026gt;). Caso contrário, T é tratado como Any? e o método não estará disponível.\nIgnorar a nullability de type parameters: por padrão, \u0026lt;T\u0026gt; pode ser nullable (T aceita String?). Se você precisa garantir que T nunca será null, use \u0026lt;T : Any\u0026gt; como upper bound.\nConclusão e Próximos Passos Generics são essenciais para escrever código Kotlin robusto e reutilizável. Neste tutorial, você aprendeu type parameters, constraints com upper bounds, variance com in/out, star projection, reified type parameters e type erasure. Esses conceitos formam a base para entender APIs complexas como as de coleções, coroutines e frameworks como Ktor e Spring.\nPara continuar aprofundando, explore:\nSealed Classes para hierarquias de tipos genéricos Extension Functions genéricas Lambdas com tipos genéricos em higher-order functions Coroutines que usam generics extensivamente (Deferred\u0026lt;T\u0026gt;, Flow\u0026lt;T\u0026gt;) Pratique criando suas próprias classes e funções genéricas. Comece simples e vá adicionando constraints e variance conforme a necessidade. Com o tempo, generics se tornarão naturais no seu código Kotlin.\n","permalink":"https://kotlin.dev.br/tutoriais/generics-kotlin/","summary":"\u003cp\u003eNeste tutorial, você vai aprender tudo sobre \u003cstrong\u003eGenerics em Kotlin\u003c/strong\u003e — um recurso fundamental para escrever código reutilizável e type-safe. Generics permitem criar classes, interfaces e funções que operam com diferentes tipos sem sacrificar a segurança de tipos do compilador. Ao final, você vai dominar type parameters, constraints, variance com \u003ccode\u003ein\u003c/code\u003e/\u003ccode\u003eout\u003c/code\u003e, star projection e reified type parameters.\u003c/p\u003e\n\u003ch2 id=\"o-que-são-generics\"\u003eO que São Generics?\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"/glossario/generics/\"\u003eGenerics\u003c/a\u003e permitem que você escreva código que funciona com qualquer tipo, enquanto ainda mantém a verificação de tipos em tempo de compilação. Sem generics, você teria que usar \u003ccode\u003eAny\u003c/code\u003e e fazer casts manuais, perdendo a segurança de tipos.\u003c/p\u003e","title":"Generics em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Kotlin e TypeScript são duas linguagens modernas com tipagem forte que competem cada vez mais no espaco de desenvolvimento backend e fullstack. Enquanto TypeScript domina o ecossistema web com Node.js, Kotlin traz a robustez da JVM é um sistema de tipos ainda mais poderoso. Vamos explorar as diferenças em profundidade.\nContexto e Filosofia TypeScript foi criada pela Microsoft em 2012 como um superset tipado do JavaScript. Seu objetivo e adicionar segurança de tipos ao ecossistema JS, mantendo compatibilidade total. Isso e ao mesmo tempo sua maior forca e sua maior limitacao.\nKotlin foi criada pela JetBrains como uma linguagem moderna para a JVM. Nao carrega o legado de outra linguagem e foi projetada do zero com null safety, coroutines e outros recursos avançados.\nSistema de Tipos Null Safety A diferenca mais impactante no dia a dia e como cada linguagem trata valores nulos.\n// Kotlin - Null safety e parte da linguagem data class Pedido( val id: String, val cliente: Cliente, val items: List\u0026lt;Item\u0026gt;, val desconto: Double? // Explicitamente nullable ) fun calcularTotal(pedido: Pedido): Double { val subtotal = pedido.items.sumOf { it.preco * it.quantidade } val desconto = pedido.desconto ?: 0.0 // Elvis operator return subtotal * (1 - desconto) } Em TypeScript, strict mode e optional chaining ajudam, mas o sistema de tipos e \u0026ldquo;apagado\u0026rdquo; em runtime. Isso significa que os tipos são verificados apenas em tempo de compilação e podem ser facilmente burlados com any ou type assertions.\nKotlin vai além: null safety e enforced em runtime, sealed classes garantem exaustividade e smart casts eliminam a necessidade de casts manuais.\nSealed Classes vs Union Types // Kotlin - Sealed classes com exaustividade garantida sealed class Resultado\u0026lt;out T\u0026gt; { data class Sucesso\u0026lt;T\u0026gt;(val dados: T) : Resultado\u0026lt;T\u0026gt;() data class Erro(val mensagem: String, val codigo: Int) : Resultado\u0026lt;Nothing\u0026gt;() data object Carregando : Resultado\u0026lt;Nothing\u0026gt;() } fun \u0026lt;T\u0026gt; tratar(resultado: Resultado\u0026lt;T\u0026gt;): String { return when (resultado) { is Resultado.Sucesso -\u0026gt; \u0026#34;Dados: ${resultado.dados}\u0026#34; is Resultado.Erro -\u0026gt; \u0026#34;Erro ${resultado.codigo}: ${resultado.mensagem}\u0026#34; is Resultado.Carregando -\u0026gt; \u0026#34;Carregando...\u0026#34; } // Compilador garante todos os casos cobertos } TypeScript tem union types que são poderosos, mas não oferecem a mesma garantia de exaustividade em todos os cenários. Kotlin sealed classes são hierarquias de tipos reais, com todas as vantagens de heranca e pattern matching.\nProgramação Assíncrona Essa e uma area onde Kotlin brilha de verdade.\n// Kotlin Coroutines - Structured concurrency class PedidoService( private val pedidoRepo: PedidoRepository, private val estoqueService: EstoqueService, private val notificacaoService: NotificacaoService ) { suspend fun processarPedido(pedido: NovoPedido): Pedido { // Execução paralela com cancelamento automatico return coroutineScope { val validação = async { validarPedido(pedido) } val estoque = async { estoqueService.verificar(pedido.items) } // Se qualquer um falhar, o outro e cancelado automaticamente validação.await() estoque.await() val pedidoCriado = pedidoRepo.salvar(pedido.toPedido()) // Fire and forget com escopo controlado launch { notificacaoService.enviar(pedidoCriado) } pedidoCriado } } } Kotlin Coroutines oferecem structured concurrency, que garante que nenhuma coroutine \u0026ldquo;vaza\u0026rdquo;. Em TypeScript com async/await, e muito fácil criar Promises que não são awaited, causando erros silenciosos.\nAlem disso, Kotlin Flow oferece programação reativa integrada:\n// Kotlin Flow - Stream de dados reativo fun monitorarPrecos(produtoId: String): Flow\u0026lt;Preco\u0026gt; { return flow { while (true) { val preco = api.getPreco(produtoId) emit(preco) delay(5000) // Verifica a cada 5 segundos } } .distinctUntilChanged() .onEach { preco -\u0026gt; logger.info(\u0026#34;Preco atualizado: $preco\u0026#34;) } .catch { e -\u0026gt; logger.error(\u0026#34;Erro ao buscar preco\u0026#34;, e) } } Performance e Escalabilidade A JVM e uma maquina de performance. Decadas de otimização, JIT compilation e garbage collectors sofisticados fazem do Kotlin uma escolha excelente para aplicações de alta carga.\n// Kotlin com Ktor - API de alta performance fun Application.configurarRoteamento() { routing { route(\u0026#34;/api/v1/produtos\u0026#34;) { get { val pagina = call.request.queryParameters[\u0026#34;pagina\u0026#34;]?.toIntOrNull() ?: 1 val tamanho = call.request.queryParameters[\u0026#34;tamanho\u0026#34;]?.toIntOrNull() ?: 20 val produtos = produtoService.listar(pagina, tamanho) call.respond(produtos) } get(\u0026#34;/{id}\u0026#34;) { val id = call.parameters[\u0026#34;id\u0026#34;] ?: return@get call.respond(HttpStatusCode.BadRequest) val produto = produtoService.buscar(id) ?: return@get call.respond(HttpStatusCode.NotFound) call.respond(produto) } } } } Node.js com TypeScript e single-threaded por natureza. Para I/O bound workloads, funciona bem. Mas para CPU bound tasks ou aplicações que precisam de true parallelism, a JVM com Kotlin e muito superior.\nEm benchmarks do TechEmpower (um dos mais respeitados para web frameworks), frameworks JVM como Ktor e Spring consistentemente superam frameworks Node.js em throughput e latencia.\nEcossistema para Backend Kotlin Spring Boot: O framework enterprise mais usado do mundo, com suporte de primeira classe para Kotlin Ktor: Framework nativo Kotlin, leve e performatico Exposed: ORM nativo Kotlin com DSL type-safe kotlinx.serialization: serialização nativa e eficiente TypeScript Express/Fastify: Frameworks web leves e populares NestJS: Framework enterprise inspirado no Angular Prisma: ORM moderno com boa DX tRPC: Type-safe APIs end-to-end O ecossistema TypeScript e vasto, mas a qualidade varia muito. No mundo JVM com Kotlin, as bibliotecas tendem a ser mais maduras e battle-tested em producao enterprise.\nExperiência de Desenvolvimento Tooling Kotlin tem uma vantagem significativa em ferramentas. IntelliJ IDEA (criada pelo mesmo time que criou Kotlin) oferece refactoring, análise de código e debugging que são simplesmente superiores a qualquer editor TypeScript.\n// Kotlin DSL para configuracao type-safe object DatabaseConfig { fun configure(): HikariConfig { return HikariConfig().apply { jdbcUrl = System.getenv(\u0026#34;DATABASE_URL\u0026#34;) maximumPoolSize = 10 minimumIdle = 2 idleTimeout = 30000 connectionTimeout = 20000 maxLifetime = 1800000 } } } Tempo de Build TypeScript tem vantagem no tempo de build e startup. Compilação TypeScript e rápida e Node.js inicia em milissegundos. Kotlin na JVM tem cold start mais lento, embora em producao isso raramente seja um problema (a JVM fica mais rápida com o tempo gracas ao JIT).\nFullstack com Cada Linguagem TypeScript tem a vantagem obvia de poder ser usada tanto no frontend (React, Vue, Angular) quanto no backend (Node.js). Isso permite compartilhar tipos e lógica entre camadas.\nKotlin esta expandindo nessa direcao com Kotlin/JS e Compose for Web, mas o ecossistema frontend ainda não compete com TypeScript nesse aspecto. Onde Kotlin brilha no fullstack e na combinacao mobile (Android + iOS via KMP) + backend (Spring/Ktor).\nMercado de Trabalho No Brasil, TypeScript tem mais vagas em números absolutos, impulsionado pela ubiquidade do desenvolvimento web. Porem, vagas Kotlin tendem a ser mais bem remuneradas, especialmente em empresas enterprise, bancos e fintechs.\nA demanda por desenvolvedores Kotlin esta crescendo consistentemente, e a concorrência por vagas e menor, o que significa que profissionais qualificados em Kotlin tem alto poder de negociacao.\nConclusão Se você vem do mundo JavaScript e quer adicionar tipagem ao seu workflow, TypeScript e a evolução natural. Se você quer uma linguagem com sistema de tipos verdadeiramente robusto, performance enterprise e versatilidade que vai de mobile a backend, Kotlin e a escolha superior.\nAmbas são excelentes linguagens, mas para projetos que exigem confiabilidade, performance e manutenção a longo prazo, Kotlin oferece garantias que TypeScript simplesmente não consegue igualar por conta de suas raizes no JavaScript. Outras linguagens com sistemas de tipos robustos incluem Rust e Go. Invista tempo em aprender Kotlin e você tera acesso a um ecossistema poderoso que só cresce.\n","permalink":"https://kotlin.dev.br/blog/kotlin-vs-typescript/","summary":"\u003cp\u003eKotlin e TypeScript são duas linguagens modernas com tipagem forte que competem cada vez mais no espaco de desenvolvimento backend e fullstack. Enquanto TypeScript domina o ecossistema web com Node.js, Kotlin traz a robustez da JVM é um sistema de tipos ainda mais poderoso. Vamos explorar as diferenças em profundidade.\u003c/p\u003e\n\u003ch2 id=\"contexto-e-filosofia\"\u003eContexto e Filosofia\u003c/h2\u003e\n\u003cp\u003eTypeScript foi criada pela Microsoft em 2012 como um superset tipado do JavaScript. Seu objetivo e adicionar segurança de tipos ao ecossistema JS, mantendo compatibilidade total. Isso e ao mesmo tempo sua maior forca e sua maior limitacao.\u003c/p\u003e","title":"Kotlin vs TypeScript: Backend e Fullstack em Foco | Kotlin Brasil"},{"content":"Neste tutorial, você vai aprender tudo sobre Sealed Classes em Kotlin — um recurso poderoso para representar hierarquias de tipos restritas. Sealed classes permitem que o compilador saiba exatamente quais subtipos existem, habilitando verificações exaustivas com when e padrões robustos de gerenciamento de estado e tratamento de erros. Ao final, você vai dominar sealed classes, sealed interfaces e saber aplicá-las em cenários reais.\nO que São Sealed Classes? Uma sealed class é uma classe abstrata cujas subclasses são conhecidas em tempo de compilação. Todas as subclasses diretas de uma sealed class devem ser declaradas no mesmo pacote (e, antes do Kotlin 1.5, no mesmo arquivo). Isso cria uma hierarquia de tipos fechada — nenhum código externo pode adicionar novos subtipos.\nPense em sealed classes como enums turbinadas. Enquanto enums definem um conjunto fixo de valores constantes, sealed classes definem um conjunto fixo de tipos, cada um podendo carregar dados diferentes.\nSintaxe Básica sealed class Resultado { data class Sucesso(val dados: String) : Resultado() data class Erro(val mensagem: String, val codigo: Int) : Resultado() object Carregando : Resultado() } Cada subtipo pode ser:\nUma data class — quando precisa carregar dados Uma class regular — quando tem comportamento próprio Um object — quando representa um estado singleton (sem dados) Expressões When com Sealed Classes A maior vantagem de sealed classes aparece quando combinadas com expressões when. O compilador sabe exatamente quais subtipos existem e garante que você trate todos os casos:\nfun processarResultado(resultado: Resultado): String { return when (resultado) { is Resultado.Sucesso -\u0026gt; \u0026#34;Dados: ${resultado.dados}\u0026#34; is Resultado.Erro -\u0026gt; \u0026#34;Erro ${resultado.codigo}: ${resultado.mensagem}\u0026#34; is Resultado.Carregando -\u0026gt; \u0026#34;Aguarde...\u0026#34; // Sem branch \u0026#39;else\u0026#39; necessario! O compilador verifica exaustivamente. } } fun main() { val r1 = Resultado.Sucesso(\u0026#34;Lista de usuários carregada\u0026#34;) val r2 = Resultado.Erro(\u0026#34;Não encontrado\u0026#34;, 404) val r3 = Resultado.Carregando println(processarResultado(r1)) // Dados: Lista de usuários carregada println(processarResultado(r2)) // Erro 404: Não encontrado println(processarResultado(r3)) // Aguarde... } Se você adicionar um novo subtipo à sealed class, o compilador mostrará erros em todos os when que não tratam o novo caso. Isso é extremamente valioso para manutenção do código — bugs são capturados em tempo de compilação, não em tempo de execução.\nSealed Classes vs Enums Embora pareçam similares, sealed classes e enums resolvem problemas diferentes:\n// Enum: cada valor e uma instância ÚNICA e constante enum class Direcao { NORTE, SUL, LESTE, OESTE } // Sealed class: cada subtipo pode ter MÚLTIPLAS instâncias com dados diferentes sealed class Evento { data class Click(val x: Int, val y: Int) : Evento() data class Tecla(val codigo: Int, val modificadores: Set\u0026lt;String\u0026gt;) : Evento() data class Scroll(val deltaX: Double, val deltaY: Double) : Evento() object Foco : Evento() object PerderaFoco : Evento() } fun main() { // Enum: só existe UM Direcao.NORTE val dir = Direcao.NORTE // Sealed: podem existir muitos Click diferentes val click1 = Evento.Click(100, 200) val click2 = Evento.Click(300, 400) // click1 e click2 são instâncias diferentes do mesmo tipo } Use enum quando: os valores são fixos e não carregam dados variáveis. Use sealed class quando: os tipos são fixos, mas cada instância pode ter dados próprios.\nSealed Interfaces (Kotlin 1.5+) A partir do Kotlin 1.5, você pode declarar sealed interfaces. Isso é poderoso porque uma classe pode implementar múltiplas sealed interfaces, algo impossível com sealed classes (herança simples):\nsealed interface Validavel { fun validar(): Boolean } sealed interface Serializavel { fun toJson(): String } // Uma classe pode implementar ambas as sealed interfaces data class Email(val endereco: String) : Validavel, Serializavel { override fun validar(): Boolean = endereco.contains(\u0026#34;@\u0026#34;) override fun toJson(): String = \u0026#34;\u0026#34;\u0026#34;{\u0026#34;email\u0026#34;: \u0026#34;$endereco\u0026#34;}\u0026#34;\u0026#34;\u0026#34; } data class Telefone(val numero: String) : Validavel, Serializavel { override fun validar(): Boolean = numero.length \u0026gt;= 10 override fun toJson(): String = \u0026#34;\u0026#34;\u0026#34;{\u0026#34;telefone\u0026#34;: \u0026#34;$numero\u0026#34;}\u0026#34;\u0026#34;\u0026#34; } data class Endereco(val rua: String) : Validavel { override fun validar(): Boolean = rua.isNotBlank() } fun processarValidavel(item: Validavel) { when (item) { is Email -\u0026gt; println(\u0026#34;Email: ${item.endereco} — Válido: ${item.validar()}\u0026#34;) is Telefone -\u0026gt; println(\u0026#34;Tel: ${item.numero} — Válido: ${item.validar()}\u0026#34;) is Endereco -\u0026gt; println(\u0026#34;End: ${item.rua} — Válido: ${item.validar()}\u0026#34;) } } Sealed interfaces expandem enormemente as possibilidades de modelagem de tipos em Kotlin.\nPadrão de Gerenciamento de Estado Sealed classes são ideais para representar estados de UI, especialmente em aplicações Android com ViewModel:\nsealed class UiState\u0026lt;out T\u0026gt; { object Carregando : UiState\u0026lt;Nothing\u0026gt;() data class Sucesso\u0026lt;T\u0026gt;(val dados: T) : UiState\u0026lt;T\u0026gt;() data class Erro(val excecao: Throwable) : UiState\u0026lt;Nothing\u0026gt;() object Vazio : UiState\u0026lt;Nothing\u0026gt;() } // Simulação de ViewModel class UsuarioViewModel { private var estado: UiState\u0026lt;List\u0026lt;String\u0026gt;\u0026gt; = UiState.Carregando fun carregarUsuarios() { estado = UiState.Carregando try { // Simulando chamada de API val usuarios = listOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;, \u0026#34;Carla\u0026#34;) estado = if (usuarios.isEmpty()) { UiState.Vazio } else { UiState.Sucesso(usuarios) } } catch (e: Exception) { estado = UiState.Erro(e) } } fun renderizar() { when (val s = estado) { is UiState.Carregando -\u0026gt; println(\u0026#34;Exibindo spinner...\u0026#34;) is UiState.Sucesso -\u0026gt; println(\u0026#34;Usuários: ${s.dados.joinToString()}\u0026#34;) is UiState.Erro -\u0026gt; println(\u0026#34;Erro: ${s.excecao.message}\u0026#34;) is UiState.Vazio -\u0026gt; println(\u0026#34;Nenhum usuário encontrado\u0026#34;) } } } fun main() { val viewModel = UsuarioViewModel() viewModel.renderizar() // Exibindo spinner... viewModel.carregarUsuarios() viewModel.renderizar() // Usuários: Ana, Bruno, Carla } Este padrão é amplamente usado em projetos Android modernos com Jetpack Compose e é considerado uma das melhores práticas para gerenciar estados de interface.\nPadrão de Tratamento de Erros Sealed classes oferecem uma alternativa elegante a exceptions para representar resultados que podem falhar:\nsealed class Resultado\u0026lt;out T\u0026gt; { data class Ok\u0026lt;T\u0026gt;(val valor: T) : Resultado\u0026lt;T\u0026gt;() sealed class Falha : Resultado\u0026lt;Nothing\u0026gt;() { data class NaoEncontrado(val recurso: String) : Falha() data class SemPermissao(val acao: String) : Falha() data class ErroDeRede(val causa: Throwable) : Falha() data class Validação(val campos: Map\u0026lt;String, String\u0026gt;) : Falha() } } fun buscarUsuario(id: Long): Resultado\u0026lt;String\u0026gt; { if (id \u0026lt;= 0) return Resultado.Falha.Validação(mapOf(\u0026#34;id\u0026#34; to \u0026#34;deve ser positivo\u0026#34;)) if (id == 999L) return Resultado.Falha.NaoEncontrado(\u0026#34;Usuário #$id\u0026#34;) return Resultado.Ok(\u0026#34;Usuário #$id encontrado\u0026#34;) } fun main() { val ids = listOf(1L, -5L, 999L) ids.forEach { id -\u0026gt; when (val resultado = buscarUsuario(id)) { is Resultado.Ok -\u0026gt; println(\u0026#34;Sucesso: ${resultado.valor}\u0026#34;) is Resultado.Falha.NaoEncontrado -\u0026gt; println(\u0026#34;404: ${resultado.recurso}\u0026#34;) is Resultado.Falha.SemPermissao -\u0026gt; println(\u0026#34;403: ${resultado.acao}\u0026#34;) is Resultado.Falha.ErroDeRede -\u0026gt; println(\u0026#34;Rede: ${resultado.causa.message}\u0026#34;) is Resultado.Falha.Validação -\u0026gt; println(\u0026#34;Validação: ${resultado.campos}\u0026#34;) } } } Note que sealed classes podem ter subclasses que também são sealed, criando hierarquias de tipos ricas e expressivas.\nSealed Classes com Generics Combinando sealed classes com generics, você cria estruturas extremamente reutilizáveis:\nsealed class Arvore\u0026lt;out T\u0026gt; { object Vazia : Arvore\u0026lt;Nothing\u0026gt;() data class No\u0026lt;T\u0026gt;(val valor: T, val esquerda: Arvore\u0026lt;T\u0026gt;, val direita: Arvore\u0026lt;T\u0026gt;) : Arvore\u0026lt;T\u0026gt;() } fun \u0026lt;T\u0026gt; Arvore\u0026lt;T\u0026gt;.tamanho(): Int = when (this) { is Arvore.Vazia -\u0026gt; 0 is Arvore.No -\u0026gt; 1 + esquerda.tamanho() + direita.tamanho() } fun \u0026lt;T\u0026gt; Arvore\u0026lt;T\u0026gt;.toList(): List\u0026lt;T\u0026gt; = when (this) { is Arvore.Vazia -\u0026gt; emptyList() is Arvore.No -\u0026gt; esquerda.toList() + valor + direita.toList() } fun main() { val arvore = Arvore.No( 10, Arvore.No(5, Arvore.Vazia, Arvore.Vazia), Arvore.No(15, Arvore.Vazia, Arvore.Vazia) ) println(\u0026#34;Tamanho: ${arvore.tamanho()}\u0026#34;) // 3 println(\u0026#34;Elementos: ${arvore.toList()}\u0026#34;) // [5, 10, 15] } Erros Comuns Esquecer de usar is no when: ao fazer pattern matching com sealed classes, cada branch precisa de is para verificar o tipo. Sem is, o compilador tentará uma comparação de igualdade, que não é o desejado.\nUsar else desnecessariamente: o poder das sealed classes está na verificação exaustiva. Adicionar um branch else desativa esse benefício — se você adicionar um novo subtipo, o else vai capturá-lo silenciosamente em vez de gerar um erro de compilação.\nConfundir sealed class com abstract class: sealed classes são restritas ao mesmo pacote. Se você precisa que código externo crie subtipos, use abstract class ou interface regular.\nNão aproveitar smart casts: dentro de um branch is do when, Kotlin faz smart cast automaticamente. Você não precisa fazer cast manual para acessar propriedades do subtipo.\nCriar hierarquias excessivamente profundas: sealed classes aninhadas em muitos níveis tornam o código difícil de manter. Mantenha a hierarquia rasa e clara.\nConclusão e Próximos Passos Sealed classes são uma das ferramentas mais poderosas de Kotlin para modelagem de domínio. Elas garantem segurança em tempo de compilação, eliminam bugs de tipos não tratados e tornam o código expressivo e autodocumentável. Neste tutorial, você aprendeu a sintaxe, a integração com when, a diferença para enums, sealed interfaces, e padrões práticos de estado e erro.\nPara aprofundar seus conhecimentos, explore:\nData Classes para usar como subtipos de sealed classes Generics para criar sealed classes parametrizadas Coroutines para usar sealed classes como resultado de operações assíncronas Extension Functions para adicionar comportamento às suas sealed classes Comece aplicando sealed classes nos seus projetos para representar estados de UI, resultados de operações e qualquer domínio com conjunto fixo de variantes. O compilador será seu aliado para manter o código seguro e completo.\n","permalink":"https://kotlin.dev.br/tutoriais/sealed-classes-tutorial/","summary":"\u003cp\u003eNeste tutorial, você vai aprender tudo sobre \u003cstrong\u003eSealed Classes em Kotlin\u003c/strong\u003e — um recurso poderoso para representar hierarquias de tipos restritas. Sealed classes permitem que o compilador saiba exatamente quais subtipos existem, habilitando verificações exaustivas com \u003ca href=\"/glossario/when/\"\u003ewhen\u003c/a\u003e e padrões robustos de gerenciamento de estado e tratamento de erros. Ao final, você vai dominar sealed classes, sealed interfaces e saber aplicá-las em cenários reais.\u003c/p\u003e\n\u003ch2 id=\"o-que-são-sealed-classes\"\u003eO que São Sealed Classes?\u003c/h2\u003e\n\u003cp\u003eUma \u003ca href=\"/glossario/sealed-class/\"\u003esealed class\u003c/a\u003e é uma classe abstrata cujas subclasses são conhecidas em tempo de compilação. Todas as subclasses diretas de uma sealed class devem ser declaradas no mesmo pacote (e, antes do Kotlin 1.5, no mesmo arquivo). Isso cria uma hierarquia de tipos \u003cstrong\u003efechada\u003c/strong\u003e — nenhum código externo pode adicionar novos subtipos.\u003c/p\u003e","title":"Sealed Classes em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Se você é um desenvolvedor Java experiente e está considerando aprender Kotlin, está no lugar certo. Kotlin foi projetada para ser totalmente interoperável com Java, o que significa que você pode adotar a linguagem gradualmente sem abandonar seu código existente. Este guia apresenta as principais diferenças, vantagens e padrões que tornarão sua transição suave e produtiva.\nPor Que Desenvolvedores Java Devem Aprender Kotlin A pergunta mais comum entre desenvolvedores Java é: \u0026ldquo;Por que eu deveria aprender mais uma linguagem?\u0026rdquo; A resposta está nos ganhos concretos de produtividade que Kotlin oferece. Estudos mostram que projetos em Kotlin tendem a ter significativamente menos linhas de código para a mesma funcionalidade, além de uma redução drástica nos erros relacionados a null.\nAs principais vantagens de Kotlin sobre Java são:\nMenos boilerplate: data classes, properties e smart casts eliminam código repetitivo Null safety nativo: o sistema de tipos previne NullPointerException em tempo de compilação Coroutines: programação assíncrona simplificada sem callbacks aninhados Extension functions: adicione funcionalidades a classes existentes sem herança Interoperabilidade total: use qualquer biblioteca Java diretamente em Kotlin O Google adotou Kotlin como linguagem preferida para Android em 2019, e frameworks como Spring Boot oferecem suporte de primeira classe à linguagem. Para uma visão mais detalhada do processo de migração de projetos inteiros, confira nosso guia de migração de Java para Kotlin.\nComparação de Sintaxe: Java vs Kotlin Vamos comparar os mesmos conceitos nas duas linguagens para que você veja as diferenças na prática.\nDeclaração de Variáveis Java:\n// Java String nome = \u0026#34;Kotlin Brasil\u0026#34;; final int idade = 5; Kotlin:\nvar nome = \u0026#34;Kotlin Brasil\u0026#34; // tipo inferido automaticamente val idade = 5 // imutável (equivalente a final) Em Kotlin, ponto e vírgula é opcional e inferência de tipos torna as declarações mais concisas. A palavra-chave val é equivalente ao final de Java, e var permite reatribuição.\nClasses e POJOs Um dos maiores ganhos de Kotlin é na criação de classes de dados. Compare o que seria necessário em Java com o equivalente em Kotlin:\nJava (sem Lombok):\n// Java - aproximadamente 50+ linhas public class Usuario { private String nome; private int idade; private String email; public Usuario(String nome, int idade, String email) { this.nome = nome; this.idade = idade; this.email = email; } // getters, setters, equals, hashCode, toString... } Kotlin:\ndata class Usuario( val nome: String, val idade: Int, val email: String ) Uma única linha em Kotlin gera automaticamente equals(), hashCode(), toString(), copy() e funções de desestruturação. Essa redução de boilerplate é um dos fatores que mais impressiona desenvolvedores Java.\nTabela Comparativa de Recursos Recurso Java Kotlin Null safety Optional (Java 8+) Integrado ao sistema de tipos Data classes Records (Java 16+) ou Lombok data class nativo Extension functions Não suportado Suportado nativamente Coroutines CompletableFuture / Reactor Coroutines nativas String templates Sem suporte nativo (Java 21+ com STR) \u0026quot;Olá, $nome\u0026quot; Smart casts Não disponível Automático após verificação Sealed classes Sealed (Java 17+) sealed class mais flexível Default parameters Não suportado Suportado nativamente Null Safety: O Fim dos NullPointerException O sistema de null safety de Kotlin é provavelmente o recurso que mais impacta a qualidade do código vindo de Java. Em Java, qualquer referência pode ser null, e o compilador não oferece proteção contra isso.\n// Em Kotlin, tipos são non-null por padrao var nome: String = \u0026#34;Kotlin\u0026#34; // nome = null // Erro de compilacao! // Para permitir null, use o operador ? var nomeNullable: String? = \u0026#34;Kotlin\u0026#34; nomeNullable = null // OK // Safe call operator val tamanho = nomeNullable?.length // retorna null se nomeNullable for null // Elvis operator (valor padrao) val tamanhoSeguro = nomeNullable?.length ?: 0 // Smart cast: após verificacao, o tipo é automaticamente refinado if (nomeNullable != null) { println(nomeNullable.length) // Não precisa de ?. aqui } Para desenvolvedores Java acostumados com Optional, o null safety de Kotlin é mais natural e abrangente, pois está integrado diretamente ao sistema de tipos da linguagem. Consulte o glossário para entender termos como safe call e Elvis operator em mais detalhes.\nExtension Functions: Estendendo Classes Sem Herança Extension functions permitem adicionar métodos a classes existentes sem modificá-las ou usar padrões como Decorator:\n// Adicionando uma funcao a String fun String.capitalizar(): String { return this.split(\u0026#34; \u0026#34;).joinToString(\u0026#34; \u0026#34;) { palavra -\u0026gt; palavra.replaceFirstChar { it.uppercase() } } } val titulo = \u0026#34;kotlin para desenvolvedores java\u0026#34; println(titulo.capitalizar()) // \u0026#34;Kotlin Para Desenvolvedores Java\u0026#34; // Extension function em Int fun Int.ehPar(): Boolean = this % 2 == 0 println(4.ehPar()) // true println(7.ehPar()) // false Isso é especialmente útil para adicionar funcionalidades a classes de bibliotecas de terceiros sem precisar criar wrappers ou classes utilitárias estáticas.\nCoroutines vs Threads e CompletableFuture Em Java, programação assíncrona geralmente envolve threads, ExecutorService ou CompletableFuture, que podem resultar em código complexo e difícil de manter. Kotlin oferece coroutines como uma solução elegante e leve:\nJava:\n// Java - CompletableFuture CompletableFuture.supplyAsync(() -\u0026gt; buscarUsuario(id)) .thenApply(usuario -\u0026gt; buscarPedidos(usuario)) .thenAccept(pedidos -\u0026gt; exibirPedidos(pedidos)) .exceptionally(ex -\u0026gt; { tratarErro(ex); return null; }); Kotlin:\n// Kotlin - Coroutines suspend fun processarPedidos(id: Int) { try { val usuario = buscarUsuario(id) // suspende sem bloquear val pedidos = buscarPedidos(usuario) // codigo sequencial! exibirPedidos(pedidos) } catch (e: Exception) { tratarErro(e) } } O código com coroutines parece sequencial, mas executa de forma assíncrona. Isso elimina o \u0026ldquo;callback hell\u0026rdquo; e torna o fluxo de erro natural com try/catch. Para dominar coroutines, recomendamos nosso guia completo de Coroutines.\nSmart Casts e Pattern Matching Em Java, após verificar o tipo de um objeto com instanceof, é necessário fazer o cast explicitamente. Em Kotlin, o compilador faz isso automaticamente:\nfun descrever(obj: Any): String { return when (obj) { is String -\u0026gt; \u0026#34;String de tamanho ${obj.length}\u0026#34; // smart cast automático is Int -\u0026gt; \u0026#34;Inteiro com valor ${obj + 1}\u0026#34; is List\u0026lt;*\u0026gt; -\u0026gt; \u0026#34;Lista com ${obj.size} elementos\u0026#34; else -\u0026gt; \u0026#34;Tipo desconhecido\u0026#34; } } O when combinado com smart casts é muito mais poderoso que o switch-case do Java, podendo fazer verificações de tipo, ranges, condições múltiplas e muito mais. Esse recurso se torna ainda mais poderoso quando combinado com sealed classes.\nInteroperabilidade com Código Java Existente Um dos pontos fortes de Kotlin é que você não precisa reescrever todo seu código Java para começar a usar Kotlin. A interoperabilidade funciona nos dois sentidos:\n// Chamando codigo Java a partir de Kotlin val lista = ArrayList\u0026lt;String\u0026gt;() // classe Java lista.add(\u0026#34;Kotlin\u0026#34;) lista.add(\u0026#34;Java\u0026#34;) // Usando bibliotecas Java (ex: Spring) @RestController class UsuarioController(private val service: UsuarioService) { @GetMapping(\u0026#34;/usuarios\u0026#34;) fun listar(): List\u0026lt;Usuario\u0026gt; = service.listarTodos() } Kotlin adiciona anotações como @JvmStatic, @JvmField e @JvmOverloads para facilitar o uso de código Kotlin a partir de Java. Isso permite uma migração gradual e segura do codebase.\nDicas Práticas para a Transição Baseado na experiência de milhares de desenvolvedores que já fizeram essa transição, aqui estão recomendações práticas:\nComece pelos testes: escrever testes unitários em Kotlin é uma forma segura de aprender a linguagem sem arriscar código de produção Use a conversão automática: IntelliJ IDEA oferece a opção de converter código Java para Kotlin automaticamente (Ctrl+Alt+Shift+K) Aprenda os idiomas de Kotlin: não escreva \u0026ldquo;Java em Kotlin\u0026rdquo; — adote data classes, extension functions e scope functions Adote gradualmente: misture arquivos Java e Kotlin no mesmo projeto e migre incrementalmente Estude as scope functions: let, run, with, apply e also são essenciais para código idiomático em Kotlin Para aprofundar seus conhecimentos em backend, consulte nosso guia de Kotlin para backend e nossos tutoriais práticos com projetos completos. Se você deseja entender como aplicar Kotlin no desenvolvimento Android, confira nosso guia completo de Kotlin para Android.\nConclusão A transição de Java para Kotlin é uma das migrações mais suaves que um desenvolvedor pode fazer. A interoperabilidade total, a familiaridade da JVM e os ganhos imediatos de produtividade tornam Kotlin uma evolução natural para qualquer desenvolvedor Java. Comece aos poucos, aproveite a conversão automática da IDE e, em poucas semanas, você estará escrevendo código Kotlin idiomático com confiança. A comunidade Kotlin Brasil está aqui para apoiar sua jornada. Se além de Kotlin você quer explorar outras linguagens modernas, Go é outra opção popular entre desenvolvedores Java e Python complementa bem o toolkit de qualquer desenvolvedor.\n","permalink":"https://kotlin.dev.br/guias/kotlin-para-desenvolvedores-java/","summary":"\u003cp\u003eSe você é um desenvolvedor Java experiente e está considerando aprender Kotlin, está no lugar certo. Kotlin foi projetada para ser totalmente interoperável com Java, o que significa que você pode adotar a linguagem gradualmente sem abandonar seu código existente. Este guia apresenta as principais diferenças, vantagens e padrões que tornarão sua transição suave e produtiva.\u003c/p\u003e\n\u003ch2 id=\"por-que-desenvolvedores-java-devem-aprender-kotlin\"\u003ePor Que Desenvolvedores Java Devem Aprender Kotlin\u003c/h2\u003e\n\u003cp\u003eA pergunta mais comum entre desenvolvedores Java é: \u0026ldquo;Por que eu deveria aprender mais uma linguagem?\u0026rdquo; A resposta está nos ganhos concretos de produtividade que Kotlin oferece. Estudos mostram que projetos em Kotlin tendem a ter significativamente menos linhas de código para a mesma funcionalidade, além de uma redução drástica nos erros relacionados a null.\u003c/p\u003e","title":"Kotlin para Desenvolvedores Java: Guia de Transição Completo | Kotlin Brasil"},{"content":"Neste tutorial, você vai aprender tudo sobre Data Classes em Kotlin — um recurso que elimina toneladas de código boilerplate que você precisaria escrever em Java. Data classes geram automaticamente métodos como equals(), hashCode(), toString(), copy() e funções componentN() para destructuring. Ao final deste guia, você saberá quando e como usá-las de forma eficiente no seu código.\nO Problema que Data Classes Resolvem Em Java, para representar uma simples classe de dados como um Usuario, você precisaria escrever manualmente: construtor, getters, setters, equals(), hashCode() e toString(). São facilmente mais de 50 linhas de código para algo conceitualmente simples.\nEm Kotlin, uma data class resolve tudo isso em uma única linha:\ndata class Usuario(val nome: String, val email: String, val idade: Int) Essa única linha gera automaticamente todos os métodos mencionados acima. Vamos explorar cada um deles em detalhes.\nSintaxe e Regras Básicas Para declarar uma data class, basta usar a palavra-chave data antes de class. Existem algumas regras que o compilador exige:\n// Data class valida data class Produto(val nome: String, val preco: Double, val categoria: String) // O construtor primário PRECISA ter pelo menos um parâmetro // Todos os parâmetros do construtor primário devem ser val ou var Regras obrigatórias para data classes:\nO construtor primário precisa ter pelo menos um parâmetro Cada parâmetro do construtor primário deve ser marcado como val ou var Data classes não podem ser abstract, open, sealed ou inner Métodos Gerados Automaticamente toString() O toString() gerado é extremamente útil para debugging e logging:\ndata class Livro(val titulo: String, val autor: String, val paginas: Int) val livro = Livro(\u0026#34;O Senhor dos Anéis\u0026#34;, \u0026#34;Tolkien\u0026#34;, 1200) println(livro) // Livro(titulo=O Senhor dos Anéis, autor=Tolkien, paginas=1200) Compare com uma classe regular, que imprimiria algo como Livro@1a2b3c4d. A data class mostra todos os valores de forma legível.\nequals() e hashCode() Data classes comparam por valor, não por referência. Dois objetos com os mesmos dados são considerados iguais:\ndata class Ponto(val x: Int, val y: Int) val p1 = Ponto(3, 7) val p2 = Ponto(3, 7) val p3 = Ponto(1, 5) println(p1 == p2) // true — mesmos valores println(p1 == p3) // false — valores diferentes println(p1 === p2) // false — referências diferentes (são objetos distintos) // hashCode tambem é consistente val conjunto = hashSetOf(p1, p2, p3) println(conjunto.size) // 2 — p1 e p2 são \u0026#34;iguais\u0026#34; Isso é fundamental para usar data classes como chaves em Map, em Set, ou em qualquer situação que dependa de igualdade estrutural.\ncopy() O método copy() cria uma cópia do objeto, permitindo alterar apenas algumas propriedades. Isso é essencial para trabalhar com objetos imutáveis (declarados com val):\ndata class Configuração( val tema: String, val idioma: String, val notificacoes: Boolean, val fontSize: Int ) val configOriginal = Configuração(\u0026#34;escuro\u0026#34;, \u0026#34;pt-BR\u0026#34;, true, 16) // Alterar apenas o tema e o tamanho da fonte val configNova = configOriginal.copy(tema = \u0026#34;claro\u0026#34;, fontSize = 18) println(configOriginal) // Configuração(tema=escuro, idioma=pt-BR, notificacoes=true, fontSize=16) println(configNova) // Configuração(tema=claro, idioma=pt-BR, notificacoes=true, fontSize=18) O copy() é a base para o padrão de imutabilidade em Kotlin. Em vez de modificar um objeto existente, você cria uma nova versão com as alterações desejadas.\ncomponentN() e Destructuring Data classes geram funções component1(), component2(), etc., correspondendo à ordem dos parâmetros no construtor. Isso habilita o destructuring:\ndata class Endereco(val rua: String, val numero: Int, val cidade: String) val endereco = Endereco(\u0026#34;Av. Paulista\u0026#34;, 1000, \u0026#34;São Paulo\u0026#34;) // Destructuring declaration val (rua, numero, cidade) = endereco println(\u0026#34;$rua, $numero — $cidade\u0026#34;) // Av. Paulista, 1000 — São Paulo // Funciona em loops tambem val enderecos = listOf( Endereco(\u0026#34;Rua A\u0026#34;, 10, \u0026#34;SP\u0026#34;), Endereco(\u0026#34;Rua B\u0026#34;, 20, \u0026#34;RJ\u0026#34;), Endereco(\u0026#34;Rua C\u0026#34;, 30, \u0026#34;BH\u0026#34;) ) for ((r, n, c) in enderecos) { println(\u0026#34;$r, $n — $c\u0026#34;) } // E com lambdas! enderecos.forEach { (r, _, c) -\u0026gt; // _ ignora o numero println(\u0026#34;$r em $c\u0026#34;) } Propriedades Fora do Construtor Primário Propriedades declaradas dentro do corpo da data class não participam dos métodos gerados:\ndata class Aluno(val nome: String, val matricula: Int) { var notaFinal: Double = 0.0 // NÃO participa de equals, hashCode, toString, copy } val a1 = Aluno(\u0026#34;Maria\u0026#34;, 12345) a1.notaFinal = 9.5 val a2 = Aluno(\u0026#34;Maria\u0026#34;, 12345) a2.notaFinal = 7.0 println(a1 == a2) // true! — notaFinal NÃO é considerada println(a1) // Aluno(nome=Maria, matricula=12345) — sem notaFinal Isso é intencional: apenas as propriedades do construtor primário definem a \u0026ldquo;identidade\u0026rdquo; do objeto. Use essa separação estrategicamente.\nData Class vs Classe Regular Quando usar data class e quando usar uma classe regular? Aqui está um comparativo claro:\n// USE Data Class quando: // - O objetivo principal é armazenar dados // - Você precisa de equals/hashCode baseado em valores // - Quer destructuring ou copy() data class PedidoItem(val produtoId: Long, val quantidade: Int, val precoUnitario: Double) // USE Classe Regular quando: // - A classe tem comportamento complexo // - Identidade é baseada em referência, nao em valores // - Precisa de herança (data classes nao podem ser open) class CarrinhoDeCompras { private val itens = mutableListOf\u0026lt;PedidoItem\u0026gt;() fun adicionar(item: PedidoItem) { itens.add(item) } fun total(): Double = itens.sumOf { it.precoUnitario * it.quantidade } fun limpar() { itens.clear() } } Limitações de Data Classes Existem limitações importantes que você deve conhecer:\n// 1. Data classes NÃO podem ser open (nao permitem herança direta) // data class Base(val x: Int) — nao pode ser herdada // class Filha(x: Int, val y: Int) : Base(x) — ERRO! // 2. Solução: use interfaces ou sealed classes interface Forma { fun area(): Double } data class Circulo(val raio: Double) : Forma { override fun area() = Math.PI * raio * raio } data class Retangulo(val largura: Double, val altura: Double) : Forma { override fun area() = largura * altura } // 3. Data classes podem implementar interfaces normalmente // 4. Data classes PODEM ser combinadas com sealed classes Exemplo Prático Completo Vamos criar um sistema de gerenciamento de tarefas usando data classes:\nenum class Prioridade { BAIXA, MEDIA, ALTA, URGENTE } enum class Status { PENDENTE, EM_ANDAMENTO, CONCLUIDA, CANCELADA } data class Tarefa( val id: Long, val titulo: String, val descricao: String, val prioridade: Prioridade, val status: Status = Status.PENDENTE, val tags: List\u0026lt;String\u0026gt; = emptyList() ) fun main() { val tarefas = listOf( Tarefa(1, \u0026#34;Configurar CI/CD\u0026#34;, \u0026#34;Pipeline do GitHub Actions\u0026#34;, Prioridade.ALTA, tags = listOf(\u0026#34;devops\u0026#34;)), Tarefa(2, \u0026#34;Corrigir bug login\u0026#34;, \u0026#34;Erro 401 no OAuth\u0026#34;, Prioridade.URGENTE, Status.EM_ANDAMENTO, listOf(\u0026#34;bug\u0026#34;, \u0026#34;auth\u0026#34;)), Tarefa(3, \u0026#34;Atualizar README\u0026#34;, \u0026#34;Documentar nova API\u0026#34;, Prioridade.BAIXA, tags = listOf(\u0026#34;docs\u0026#34;)), Tarefa(4, \u0026#34;Refatorar módulo X\u0026#34;, \u0026#34;Aplicar SOLID\u0026#34;, Prioridade.MEDIA, tags = listOf(\u0026#34;refactor\u0026#34;)) ) // Filtrar e transformar usando destructuring val urgentes = tarefas .filter { it.prioridade == Prioridade.URGENTE || it.prioridade == Prioridade.ALTA } .sortedBy { it.prioridade } println(\u0026#34;=== Tarefas Prioritárias ===\u0026#34;) urgentes.forEach { (id, titulo, _, prioridade, status) -\u0026gt; println(\u0026#34;#$id — $titulo [$prioridade] ($status)\u0026#34;) } // Usar copy para atualizar status val tarefaAtualizada = tarefas[0].copy(status = Status.CONCLUIDA) println(\u0026#34;\\nAtualizada: $tarefaAtualizada\u0026#34;) // Agrupar por status val porStatus = tarefas.groupBy { it.status } porStatus.forEach { (status, lista) -\u0026gt; println(\u0026#34;\\n$status: ${lista.map { it.titulo }}\u0026#34;) } } Erros Comuns Colocar propriedades mutáveis no construtor primário: usar var no construtor de data classes pode gerar bugs, pois equals() e hashCode() dependem dos valores. Se o valor mudar após inserir o objeto em um Set ou como chave de um Map, você pode perder o acesso a ele. Prefira val.\nEsperar que propriedades do corpo participem de equals(): como vimos, propriedades declaradas dentro do corpo da classe são ignoradas pelos métodos gerados. Isso é confuso para iniciantes e pode gerar comparações inesperadas.\nTentar herdar de uma data class: data classes não podem ser open. Se você precisa de hierarquias, use sealed classes combinadas com data classes ou use interfaces.\nAbusar de data classes para tudo: nem toda classe deve ser uma data class. Classes com comportamento complexo, efeitos colaterais no construtor ou identidade baseada em referência devem ser classes regulares.\nEsquecer que copy() é shallow: o copy() cria uma cópia rasa. Se a data class contém listas ou outros objetos mutáveis, a cópia compartilhará as mesmas referências internas.\nConclusão e Próximos Passos Data classes são um dos recursos mais práticos de Kotlin, eliminando centenas de linhas de boilerplate e tornando o código mais seguro e expressivo. Você aprendeu a sintaxe, os métodos gerados automaticamente, destructuring, o método copy(), as diferenças entre data classes e classes regulares, e as limitações que precisa conhecer.\nPara continuar aprendendo, explore estes tópicos relacionados:\nSealed Classes para criar hierarquias de tipos com data classes Extension Functions para adicionar funcionalidades às suas data classes Lambdas para trabalhar com coleções de data classes de forma funcional Generics para criar data classes parametrizadas Comece a usar data classes sempre que precisar representar dados. Elas são a ferramenta certa para DTOs, modelos de domínio, respostas de API e qualquer estrutura cujo propósito principal seja carregar informação.\n","permalink":"https://kotlin.dev.br/tutoriais/data-classes-tutorial/","summary":"\u003cp\u003eNeste tutorial, você vai aprender tudo sobre \u003cstrong\u003eData Classes em Kotlin\u003c/strong\u003e — um recurso que elimina toneladas de código boilerplate que você precisaria escrever em Java. Data classes geram automaticamente métodos como \u003ccode\u003eequals()\u003c/code\u003e, \u003ccode\u003ehashCode()\u003c/code\u003e, \u003ccode\u003etoString()\u003c/code\u003e, \u003ccode\u003ecopy()\u003c/code\u003e e funções \u003ccode\u003ecomponentN()\u003c/code\u003e para \u003ca href=\"/glossario/destructuring/\"\u003edestructuring\u003c/a\u003e. Ao final deste guia, você saberá quando e como usá-las de forma eficiente no seu código.\u003c/p\u003e\n\u003ch2 id=\"o-problema-que-data-classes-resolvem\"\u003eO Problema que Data Classes Resolvem\u003c/h2\u003e\n\u003cp\u003eEm Java, para representar uma simples classe de dados como um \u003ccode\u003eUsuario\u003c/code\u003e, você precisaria escrever manualmente: construtor, getters, setters, \u003ccode\u003eequals()\u003c/code\u003e, \u003ccode\u003ehashCode()\u003c/code\u003e e \u003ccode\u003etoString()\u003c/code\u003e. São facilmente mais de 50 linhas de código para algo conceitualmente simples.\u003c/p\u003e","title":"Data Classes em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Neste tutorial, você vai aprender tudo sobre Extension Functions em Kotlin — um dos recursos mais elegantes da linguagem. Extension functions permitem adicionar novas funcionalidades a classes existentes sem precisar herdar delas ou usar padrões como Decorator. Ao final, você vai dominar a sintaxe, entender extension properties, trabalhar com nullable receivers, generics e aplicar esse conhecimento em casos de uso práticos do dia a dia.\nO que São Extension Functions? Uma extension function é uma função que \u0026ldquo;estende\u0026rdquo; uma classe existente com um novo comportamento, sem modificar o código-fonte original da classe. Isso é particularmente útil quando você quer adicionar métodos a classes que não controla, como classes da standard library do Kotlin, do Android SDK ou de bibliotecas de terceiros.\nEm Java, o equivalente seria criar classes utilitárias estáticas (como StringUtils, CollectionUtils). Em Kotlin, extension functions oferecem uma abordagem muito mais natural e legível.\nSintaxe Básica A sintaxe de uma extension function coloca o tipo que está sendo estendido (chamado de receiver type) antes do nome da função:\nfun String.contarPalavras(): Int { return this.trim().split(\u0026#34;\\\\s+\u0026#34;.toRegex()).size } fun main() { val texto = \u0026#34;Kotlin e uma linguagem incrível\u0026#34; println(texto.contarPalavras()) // 5 // Funciona com qualquer String println(\u0026#34;Hello World\u0026#34;.contarPalavras()) // 2 } Dentro da extension function, a palavra this se refere ao objeto receiver — neste caso, a instância de String na qual a função foi chamada. Você pode omitir this ao acessar membros do receiver, assim como faria dentro de uma função membro normal da classe.\nfun String.primeiraMaiuscula(): String { if (isEmpty()) return this return this[0].uppercase() + substring(1).lowercase() } println(\u0026#34;kotlin\u0026#34;.primeiraMaiuscula()) // Kotlin println(\u0026#34;BRASIL\u0026#34;.primeiraMaiuscula()) // Brasil Extension Properties Além de funções, você pode criar extension properties. A única restrição é que elas não podem ter backing field — ou seja, não podem armazenar estado. Elas precisam ser definidas com get() (e opcionalmente set()):\nval String.primeiraLetra: Char get() = this[0] val String.ultimaLetra: Char get() = this[length - 1] val List\u0026lt;Int\u0026gt;.media: Double get() = if (isEmpty()) 0.0 else sum().toDouble() / size fun main() { println(\u0026#34;Kotlin\u0026#34;.primeiraLetra) // K println(\u0026#34;Kotlin\u0026#34;.ultimaLetra) // n val notas = listOf(8, 7, 9, 10, 6) println(\u0026#34;Média: ${notas.media}\u0026#34;) // Média: 8.0 } Extension properties são ótimas para criar acessos legíveis a dados derivados. O código fica muito mais fluente do que chamar funções utilitárias.\nExtensions em Companion Objects Você pode estender o companion object de uma classe, permitindo criar o equivalente a métodos estáticos via extensão:\nclass Usuario(val nome: String, val email: String) { companion object } fun Usuario.Companion.fromCsv(csv: String): Usuario { val partes = csv.split(\u0026#34;,\u0026#34;) return Usuario(partes[0].trim(), partes[1].trim()) } fun main() { val usuario = Usuario.fromCsv(\u0026#34;Ana Silva, ana@email.com\u0026#34;) println(\u0026#34;${usuario.nome} — ${usuario.email}\u0026#34;) // Ana Silva — ana@email.com } Isso é especialmente útil para criar factory methods para classes de bibliotecas externas que já possuem um companion object definido.\nEscopo de Extension Functions Extension functions são resolvidas estaticamente, não dinamicamente. Isso significa que a função chamada é determinada pelo tipo declarado da variável, não pelo tipo real em tempo de execução:\nopen class Animal class Cachorro : Animal() fun Animal.descricao() = \u0026#34;Eu sou um animal\u0026#34; fun Cachorro.descricao() = \u0026#34;Eu sou um cachorro\u0026#34; fun imprimir(animal: Animal) { println(animal.descricao()) } fun main() { imprimir(Cachorro()) // \u0026#34;Eu sou um animal\u0026#34; — NÃO \u0026#34;Eu sou um cachorro\u0026#34;! } Esse comportamento é diferente de sobrescrita de métodos em classes (polimorfismo). É fundamental entender essa distinção para evitar bugs sutis.\nAlém disso, se uma extension function tem a mesma assinatura que uma função membro da classe, a função membro sempre vence:\nclass MinhaClasse { fun saudacao() = \u0026#34;Olá do membro!\u0026#34; } fun MinhaClasse.saudacao() = \u0026#34;Olá da extensão!\u0026#34; fun main() { println(MinhaClasse().saudacao()) // \u0026#34;Olá do membro!\u0026#34; } Nullable Receiver Extensions Você pode definir extension functions em tipos nullable, o que permite chamá-las mesmo quando o objeto é null:\nfun String?.ouPadrao(padrao: String = \u0026#34;N/A\u0026#34;): String { return this ?: padrao } fun Any?.descricaoSegura(): String { return this?.toString() ?: \u0026#34;null\u0026#34; } fun main() { val nome: String? = null println(nome.ouPadrao()) // N/A println(nome.ouPadrao(\u0026#34;Anônimo\u0026#34;)) // Anônimo val valor: Int? = null println(valor.descricaoSegura()) // null println(42.descricaoSegura()) // 42 } Esse padrão é muito poderoso para criar APIs seguras que lidam com nullability de forma elegante, sem poluir o código com verificações if (x != null) por toda parte.\nGeneric Extensions Combinando extension functions com generics, você pode criar funções extremamente reutilizáveis:\nfun \u0026lt;T\u0026gt; List\u0026lt;T\u0026gt;.segundoOuNull(): T? { return if (size \u0026gt;= 2) this[1] else null } fun \u0026lt;T : Comparable\u0026lt;T\u0026gt;\u0026gt; List\u0026lt;T\u0026gt;.estaOrdenada(): Boolean { for (i in 0 until size - 1) { if (this[i] \u0026gt; this[i + 1]) return false } return true } fun \u0026lt;K, V\u0026gt; Map\u0026lt;K, V\u0026gt;.imprimir() { forEach { (chave, valor) -\u0026gt; println(\u0026#34;$chave -\u0026gt; $valor\u0026#34;) } } fun main() { val numeros = listOf(10, 20, 30) println(numeros.segundoOuNull()) // 20 println(numeros.estaOrdenada()) // true val vazio = emptyList\u0026lt;String\u0026gt;() println(vazio.segundoOuNull()) // null mapOf(\u0026#34;nome\u0026#34; to \u0026#34;Ana\u0026#34;, \u0026#34;cidade\u0026#34; to \u0026#34;SP\u0026#34;).imprimir() } Casos de Uso Práticos Formatação de dados fun Double.formatarMoeda(): String { return \u0026#34;R$ ${\u0026#34;%.2f\u0026#34;.format(this).replace(\u0026#34;.\u0026#34;, \u0026#34;,\u0026#34;)}\u0026#34; } fun Long.formatarCpf(): String { val s = this.toString().padStart(11, \u0026#39;0\u0026#39;) return \u0026#34;${s.substring(0,3)}.${s.substring(3,6)}.${s.substring(6,9)}-${s.substring(9)}\u0026#34; } println(1599.90.formatarMoeda()) // R$ 1599,90 println(12345678901L.formatarCpf()) // 123.456.789-01 Validações fun String.ehEmailValido(): Boolean { return matches(Regex(\u0026#34;^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\\\.[A-Za-z]{2,}$\u0026#34;)) } fun String.ehCepValido(): Boolean { return matches(Regex(\u0026#34;^\\\\d{5}-?\\\\d{3}$\u0026#34;)) } println(\u0026#34;ana@email.com\u0026#34;.ehEmailValido()) // true println(\u0026#34;01310-100\u0026#34;.ehCepValido()) // true Simplificando Android com extensions // Exemplo típico de extension para desenvolvimento Android fun Context.toast(mensagem: String, duracao: Int = Toast.LENGTH_SHORT) { Toast.makeText(this, mensagem, duracao).show() } fun View.visivel() { visibility = View.VISIBLE } fun View.invisivel() { visibility = View.GONE } // Uso na Activity: // toast(\u0026#34;Salvo com sucesso!\u0026#34;) // meuBotao.invisivel() DSL (Domain-Specific Language) Extension functions são a base para criar DSLs em Kotlin:\nclass HtmlBuilder { private val elementos = mutableListOf\u0026lt;String\u0026gt;() fun p(texto: String) { elementos.add(\u0026#34;\u0026lt;p\u0026gt;$texto\u0026lt;/p\u0026gt;\u0026#34;) } fun h1(texto: String) { elementos.add(\u0026#34;\u0026lt;h1\u0026gt;$texto\u0026lt;/h1\u0026gt;\u0026#34;) } fun construir(): String = elementos.joinToString(\u0026#34;\\n\u0026#34;) } fun html(bloco: HtmlBuilder.() -\u0026gt; Unit): String { val builder = HtmlBuilder() builder.bloco() return builder.construir() } val pagina = html { h1(\u0026#34;Bem-vindo ao Kotlin Brasil\u0026#34;) p(\u0026#34;Aprenda Kotlin em português.\u0026#34;) p(\u0026#34;Tutoriais, glossário e muito mais.\u0026#34;) } println(pagina) Erros Comuns Esperar comportamento polimórfico: extension functions são resolvidas estaticamente. Se você precisa de polimorfismo, use funções membro com override em vez de extensions.\nAbusar de extension functions: nem tudo precisa ser uma extension. Use-as quando fizer sentido semântico — quando a função realmente \u0026ldquo;pertence\u0026rdquo; ao tipo. Funções utilitárias genéricas podem ser funções top-level normais.\nEsquecer que membros vencem extensions: se a classe já tem um método com a mesma assinatura, sua extension será ignorada silenciosamente. Sempre verifique a API da classe antes de criar uma extension.\nNão importar extensions de outros arquivos: extension functions definidas em outros pacotes precisam ser importadas com import. Se a sua extension não está disponível, verifique os imports.\nTentar armazenar estado em extension properties: extension properties não podem ter backing field. Se você precisa associar dados extras a um objeto, considere usar um Map externo ou o padrão de delegation.\nConclusão e Próximos Passos Extension functions são um dos recursos que tornam Kotlin tão expressivo e agradável de usar. Elas permitem criar código legível, modular e reutilizável sem modificar classes existentes. Neste tutorial, cobrimos a sintaxe básica, extension properties, companion object extensions, escopo e resolução estática, nullable receivers, generics e diversos casos de uso práticos.\nPara aprofundar seus conhecimentos, explore os seguintes tópicos:\nLambdas para combinar com extension functions em APIs fluentes Data Classes para entender melhor as classes que você pode estender Generics para criar extensions ainda mais flexíveis DSLs para aprender como extension functions são usadas para criar linguagens de domínio específico Comece criando extensions simples para tipos que você usa com frequência e, com o tempo, você vai desenvolver um estilo de código Kotlin verdadeiramente idiomático.\n","permalink":"https://kotlin.dev.br/tutoriais/extension-functions-tutorial/","summary":"\u003cp\u003eNeste tutorial, você vai aprender tudo sobre \u003cstrong\u003eExtension Functions em Kotlin\u003c/strong\u003e — um dos recursos mais elegantes da linguagem. Extension functions permitem adicionar novas funcionalidades a classes existentes sem precisar herdar delas ou usar padrões como Decorator. Ao final, você vai dominar a sintaxe, entender extension properties, trabalhar com nullable receivers, generics e aplicar esse conhecimento em casos de uso práticos do dia a dia.\u003c/p\u003e\n\u003ch2 id=\"o-que-são-extension-functions\"\u003eO que São Extension Functions?\u003c/h2\u003e\n\u003cp\u003eUma \u003ca href=\"/glossario/extension-function/\"\u003eextension function\u003c/a\u003e é uma função que \u0026ldquo;estende\u0026rdquo; uma classe existente com um novo comportamento, sem modificar o código-fonte original da classe. Isso é particularmente útil quando você quer adicionar métodos a classes que não controla, como classes da standard library do Kotlin, do Android SDK ou de bibliotecas de terceiros.\u003c/p\u003e","title":"Extension Functions em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Kotlin e Python são linguagens com propósitos e filosofias bem diferentes, mas que cada vez mais aparecem nas mesmas decisões de carreira e de arquitetura em 2026. Com Kotlin crescendo no backend e no Android e Python dominando ciência de dados, IA e automação, entender as diferenças entre elas é essencial para qualquer desenvolvedor que quer fazer escolhas informadas. Este guia compara as duas sem hype, com código lado a lado, para ajudar você a decidir com base no seu objetivo real.\nVisao Geral das Linguagens Python existe desde 1991 e se tornou uma das linguagens mais populares do mundo graças à sua simplicidade e versatilidade. É a linguagem padrão para data science, machine learning e automação. Se você quer se aprofundar no ecossistema Python, confira o guia completo de Python em português.\nKotlin, lançada em 2016, é mais jovem mas trouxe inovações importantes. Com tipagem estática, null safety e interoperabilidade com Java, ela conquistou rapidamente o mundo Android e está crescendo no backend. Em 2026, com o compilador K2 maduro e recursos como context parameters no Kotlin 2.2, a linguagem se consolidou como uma das opções estáticas mais produtivas do mercado.\nComparação rápida Característica Kotlin Python Tipagem Estática, com inferência Dinâmica (type hints opcionais) Plataforma principal JVM (também JS, Native, Wasm) Interpretada (CPython) Performance bruta Alta (JIT) Baixa a moderada (rápida com NumPy) Mobile First-class (Android) Praticamente inviável Ciência de dados / IA Em crescimento Dominante Concorrência Coroutines (structured concurrency) asyncio, GIL histórico Curva de aprendizado Moderada Baixa Tipagem: Estática vs Dinamica A diferenca mais fundamental entre as duas é o sistema de tipos.\n// Kotlin - Tipagem estática com inferencia val nome = \u0026#34;Kotlin Brasil\u0026#34; // Tipo inferido como String val idade: Int = 5 // Tipo explicitado // nome = 42 // ERRO de compilacao! String nao e Int fun calcularDesconto(preco: Double, percentual: Double): Double { return preco * (1 - percentual / 100) } Em Python, os tipos são dinâmicos. Você pode atribuir qualquer valor a qualquer variavel a qualquer momento. Isso traz agilidade para scripts e protótipos, mas pode causar bugs dificeis de encontrar em projetos maiores.\nA tipagem estática do Kotlin significa que erros de tipo são detectados em tempo de compilação, não em runtime. Para projetos grandes com muitos desenvolvedores, isso e uma vantagem enorme.\nNull Safety // Kotlin - Null safety no sistema de tipos fun buscarUsuario(id: String): Usuario? { return database.findById(id) // Pode retornar null } // O compilador OBRIGA voce a tratar o null val usuario = buscarUsuario(\u0026#34;123\u0026#34;) val nome = usuario?.nome ?: \u0026#34;Desconhecido\u0026#34; // Isso nao compila: // val tamanho = usuario.nome.length // ERRO: usuario pode ser null Python não tem null safety nativo. None pode aparecer em qualquer lugar e causar AttributeError em runtime. Type hints ajudam, mas não são enforced pelo interpretador.\nPerformance Kotlin compila para bytecode JVM (ou código nativo), enquanto Python e interpretado. Na prática, isso significa que Kotlin e significativamente mais rápido para a maioria das operações.\n// Kotlin - Processamento de dados com performance fun processarDados(registros: List\u0026lt;Registro\u0026gt;): Map\u0026lt;String, Estatistica\u0026gt; { return registros .asSequence() // Processamento lazy para eficiencia .filter { it.valido } .groupBy { it.categoria } .mapValues { (_, items) -\u0026gt; Estatistica( total = items.size, media = items.map { it.valor }.average(), maximo = items.maxOf { it.valor } ) } } Em benchmarks tipicos, Kotlin e entre 10x e 100x mais rápido que Python para operações computacionais puras. Para aplicações web e APIs, a diferenca e menor mas ainda significativa, especialmente sob alta carga.\nConcorrência // Kotlin Coroutines - Concorrência eficiente suspend fun buscarDadosParalelo(): DashboardData { return coroutineScope { val usuarios = async { api.getUsuarios() } val pedidos = async { api.getPedidos() } val métricas = async { api.getMetricas() } DashboardData( usuarios = usuarios.await(), pedidos = pedidos.await(), métricas = métricas.await() ) } } Kotlin Coroutines são extremamente leves e eficientes. Você pode ter milhoes de coroutines rodando simultaneamente. Python tem asyncio, mas a implementação e mais limitada e o GIL (Global Interpreter Lock) impede paralelismo real em threads. Se concorrência é prioridade, vale conhecer também as goroutines de Go, que seguem uma abordagem diferente com channels e CSP.\nEcossistema e Casos de Uso Onde Python Domina Python e imbativel em alguns dominios:\nData Science e Machine Learning: NumPy, Pandas, Scikit-learn, TensorFlow, PyTorch Automação e Scripts: Simplicidade para tarefas rápidas Prototipagem: Ideal para testar ideias rapidamente Educacao: Excelente como primeira linguagem Onde Kotlin Domina Kotlin se destaca em:\nDesenvolvimento Android: Linguagem oficial com Jetpack Compose Backend enterprise: Com Spring Boot e toda a stack JVM Microsserviços de alta performance: Com Ktor ou Spring WebFlux Multiplatform: Compartilhamento de código entre plataformas // Kotlin com Spring Boot - API REST robusta @RestController @RequestMapping(\u0026#34;/api/usuarios\u0026#34;) class UsuarioController( private val service: UsuarioService ) { @GetMapping suspend fun listar(): ResponseEntity\u0026lt;List\u0026lt;UsuarioDTO\u0026gt;\u0026gt; { val usuarios = service.listarTodos() return ResponseEntity.ok(usuarios.map { it.toDTO() }) } @PostMapping suspend fun criar( @Valid @RequestBody request: CriarUsuarioRequest ): ResponseEntity\u0026lt;UsuarioDTO\u0026gt; { val usuario = service.criar(request) return ResponseEntity .created(URI(\u0026#34;/api/usuarios/${usuario.id}\u0026#34;)) .body(usuario.toDTO()) } } Desenvolvimento Backend: Kotlin vs Python Para backend, a comparação fica mais direta. Vamos ver os pontos principais:\nFrameworks Web Kotlin tem Spring Boot (o framework Java/Kotlin mais usado no mundo enterprise) e Ktor (framework nativo Kotlin, leve e moderno). Python tem Django e FastAPI como principais opções.\n// Ktor - Framework Kotlin moderno fun Application.module() { install(ContentNegotiation) { json(Json { prettyPrint = true ignoreUnknownKeys = true }) } install(StatusPages) { exception\u0026lt;NotFoundException\u0026gt; { call, cause -\u0026gt; call.respond(HttpStatusCode.NotFound, ErrorResponse(cause.message)) } } routing { route(\u0026#34;/api/v1\u0026#34;) { get(\u0026#34;/health\u0026#34;) { call.respond(mapOf(\u0026#34;status\u0026#34; to \u0026#34;ok\u0026#34;)) } } } } Spring Boot com Kotlin oferece um ecossistema maduro com solucoes para praticamente qualquer necessidade: segurança, cache, mensageria, batch processing e muito mais. Django e robusto também, mas a performance sob carga não se compara.\nSegurança de Tipos no Backend Em projetos backend grandes, a tipagem estática do Kotlin previne uma categoria enorme de bugs:\n// Kotlin - Modelos de dominio seguros sealed class PaymentStatus { data class Pending(val createdAt: Instant) : PaymentStatus() data class Approved(val approvedAt: Instant, val transactionId: String) : PaymentStatus() data class Rejected(val reason: String) : PaymentStatus() data class Refunded(val refundedAt: Instant, val amount: BigDecimal) : PaymentStatus() } fun processarStatus(status: PaymentStatus): String { return when (status) { is PaymentStatus.Pending -\u0026gt; \u0026#34;Aguardando\u0026#34; is PaymentStatus.Approved -\u0026gt; \u0026#34;Aprovado: ${status.transactionId}\u0026#34; is PaymentStatus.Rejected -\u0026gt; \u0026#34;Rejeitado: ${status.reason}\u0026#34; is PaymentStatus.Refunded -\u0026gt; \u0026#34;Estornado: R$ ${status.amount}\u0026#34; } // Compilador garante que todos os casos são tratados } Esse tipo de segurança simplesmente não existe em Python. Você pode usar type hints e mypy, mas são verificacoes opcionais que muitos projetos não adotam.\nMercado de Trabalho No mercado brasileiro, ambas as linguagens tem forte demanda, mas em areas diferentes:\nPython: Muito procurado para data science, ML, automação e backend de startups Kotlin: Forte demanda para Android, backend enterprise (bancos, fintechs) e projetos JVM Salários tendem a ser similares em niveis equivalentes, com Kotlin tendo uma leve vantagem em posicoes senior para backend enterprise.\nIntegração Entre as Duas Uma abordagem inteligente e usar as duas linguagens onde cada uma brilha:\n// Kotlin - Chamando serviço Python de ML class RecommendationService( private val httpClient: HttpClient ) { suspend fun getRecomendacoes(userId: String): List\u0026lt;Produto\u0026gt; { val response = httpClient.get(\u0026#34;http://ml-service/recommend\u0026#34;) { parameter(\u0026#34;user_id\u0026#34;, userId) } return response.body\u0026lt;RecommendationResponse\u0026gt;().produtos } } Muitas empresas usam Kotlin para APIs e serviços de negócio, e Python para pipelines de dados e modelos de ML. Essa arquitetura aproveita o melhor de cada mundo.\nConclusão Kotlin e Python são linguagens excelentes, mas para propósitos diferentes. Se você precisa de performance, segurança de tipos e um ecossistema enterprise maduro, Kotlin é a melhor escolha. Se você está no mundo de data science, ML ou precisa de scripts rápidos, Python continua sendo a referência.\nPara desenvolvedores que querem maximizar suas oportunidades, aprender ambas é uma estratégia inteligente. Comece com Kotlin se seu foco é desenvolvimento de software (mobile ou backend) e adicione Python como ferramenta complementar para automação e dados. Outras linguagens que complementam bem o repertório de um desenvolvedor Kotlin incluem Rust para sistemas de alta performance e Go para microsserviços e infraestrutura. O mercado valoriza profissionais versáteis, e dominar linguagens com paradigmas diferentes só enriquece seu repertório técnico.\nPara seguir explorando o ecossistema Kotlin, confira o guia completo de Kotlin, o guia de backend com Ktor, o guia de backend com Spring e o roadmap de dev Android. Para referências de carreira, veja salários de dev backend Kotlin e como se tornar dev Kotlin. Para comparações relacionadas, leia Kotlin vs Java, Kotlin vs Go para backend e Ktor vs Spring Boot.\nPerguntas frequentes Kotlin é mais difícil que Python? Depende do seu histórico. Python é geralmente mais fácil como primeira linguagem pela sintaxe próxima do pseudocódigo. Kotlin exige entender tipagem estática e null safety, mas é considerada uma das linguagens estáticas mais amigáveis para iniciantes. Quem já sabe Java migra para Kotlin quase sem atrito — veja migrando de Java para Kotlin.\nQual paga mais no Brasil, Kotlin ou Python? Os salários variam por senioridade e nicho. Kotlin costuma ter salários mais altos em posições sênior de backend enterprise e Android, enquanto Python tem grande volume de vagas em dados e IA. Para referências atualizadas, consulte salários Kotlin no Brasil e o salário de dev backend Kotlin.\nPosso usar Kotlin para ciência de dados? Sim, mas o ecossistema é menor. O Kotlin DataFrame e o kernel do Kotlin para Jupyter permitem trabalhar com dados, e Kotlin serve bem a ponta de inferência de modelos de IA. Para treinamento de modelos, porém, Python ainda é dominante. Vale conhecer o Koog para agentes de IA com Kotlin e o guia de MCP com Kotlin e Ktor.\nKotlin ou Python para backend? Ambos resolvem bem. Times JVM preferem Kotlin com Spring Boot ou Ktor; times Python preferem FastAPI ou Django. Para alto throughput e baixa latência, Kotlin costuma ter vantagem. Compare os frameworks nativos em Ktor vs Spring Boot.\nQual usar para Android? Kotlin, sem dúvida. É a linguagem recomendada pelo Google, com suporte first-class no Jetpack Compose. Python não é viável para apps Android de produção. Comece pelo guia de desenvolvimento Android com Kotlin.\n","permalink":"https://kotlin.dev.br/blog/kotlin-vs-python/","summary":"\u003cp\u003eKotlin e Python são linguagens com propósitos e filosofias bem diferentes, mas que cada vez mais aparecem nas mesmas decisões de carreira e de arquitetura em 2026. Com Kotlin crescendo no backend e no Android e Python dominando ciência de dados, IA e automação, entender as diferenças entre elas é essencial para qualquer desenvolvedor que quer fazer escolhas informadas. Este guia compara as duas sem hype, com código lado a lado, para ajudar você a decidir com base no seu objetivo real.\u003c/p\u003e","title":"Kotlin vs Python em 2026: Quando Usar Cada Linguagem | Kotlin Brasil"},{"content":"Neste tutorial, vamos explorar as estruturas condicionais do Kotlin, incluindo if, when e como elas funcionam como expressões que retornam valores. Você vai aprender a controlar o fluxo do seu programa de forma clara, concisa e idiomática, aproveitando recursos exclusivos que Kotlin oferece em relação a outras linguagens.\nO if como Expressão Em Kotlin, o if funciona de duas formas: como instrução tradicional (statement) e como expressão que retorna um valor. Essa segunda forma é extremamente poderosa e elimina a necessidade do operador ternário que existe em Java e outras linguagens.\nQuando usado como instrução, o if funciona de maneira semelhante a qualquer outra linguagem de programação. Você define uma condição é o bloco de código que deve ser executado caso a condição seja verdadeira.\nfun main() { val idade = 20 // if como instrução (statement) if (idade \u0026gt;= 18) { println(\u0026#34;Você é maior de idade.\u0026#34;) } else { println(\u0026#34;Você é menor de idade.\u0026#34;) } // if como expressão (retorna um valor) val status = if (idade \u0026gt;= 18) \u0026#34;maior de idade\u0026#34; else \u0026#34;menor de idade\u0026#34; println(\u0026#34;Status: $status\u0026#34;) // if-else if encadeado como expressão val nota = 7.5 val conceito = if (nota \u0026gt;= 9.0) { \u0026#34;Excelente\u0026#34; } else if (nota \u0026gt;= 7.0) { \u0026#34;Bom\u0026#34; } else if (nota \u0026gt;= 5.0) { \u0026#34;Regular\u0026#34; } else { \u0026#34;Insuficiente\u0026#34; } println(\u0026#34;Nota: $nota — Conceito: $conceito\u0026#34;) // if com blocos maiores (última expressão e o valor retornado) val numero = 15 val resultado = if (numero % 2 == 0) { println(\u0026#34;Analisando numero par...\u0026#34;) \u0026#34;par\u0026#34; } else { println(\u0026#34;Analisando numero ímpar...\u0026#34;) \u0026#34;ímpar\u0026#34; } println(\u0026#34;O numero $numero é $resultado\u0026#34;) } Quando o if é usado como expressão, o último valor de cada bloco é o valor retornado. Isso significa que em blocos com múltiplas linhas, apenas a última linha define o valor de retorno. Note também que, quando usado como expressão, o ramo else é obrigatório — o compilador precisa garantir que sempre haverá um valor retornado.\nEssa abordagem elimina completamente a necessidade do operador ternário (condição ? verdadeiro : falso) que existe em Java, C e JavaScript. Em Kotlin, o if como expressão é a forma idiomática de fazer a mesma coisa, mas de maneira mais legível e com suporte a blocos de código completos.\nA Expressão When: O Switch Turbinado A expressão when é uma das funcionalidades mais versáteis do Kotlin. Ela substitui e supera o switch de Java, oferecendo verificação de igualdade, ranges, verificação de tipo, condições arbitrárias e muito mais, tudo em uma sintaxe limpa e expressiva.\nfun main() { // when basico (substitui switch/case) val diaDaSemana = 3 val nomeDia = when (diaDaSemana) { 1 -\u0026gt; \u0026#34;Segunda-feira\u0026#34; 2 -\u0026gt; \u0026#34;Terça-feira\u0026#34; 3 -\u0026gt; \u0026#34;Quarta-feira\u0026#34; 4 -\u0026gt; \u0026#34;Quinta-feira\u0026#34; 5 -\u0026gt; \u0026#34;Sexta-feira\u0026#34; 6 -\u0026gt; \u0026#34;Sábado\u0026#34; 7 -\u0026gt; \u0026#34;Domingo\u0026#34; else -\u0026gt; \u0026#34;Dia invalido\u0026#34; } println(\u0026#34;Dia $diaDaSemana = $nomeDia\u0026#34;) // when com múltiplos valores no mesmo ramo val mes = 8 val estacao = when (mes) { 12, 1, 2 -\u0026gt; \u0026#34;Verão\u0026#34; 3, 4, 5 -\u0026gt; \u0026#34;Outono\u0026#34; 6, 7, 8 -\u0026gt; \u0026#34;Inverno\u0026#34; 9, 10, 11 -\u0026gt; \u0026#34;Primavera\u0026#34; else -\u0026gt; \u0026#34;Mês invalido\u0026#34; } println(\u0026#34;Mês $mes = $estacao\u0026#34;) // when com ranges (intervalos) val nota = 85 val classificacao = when (nota) { in 90..100 -\u0026gt; \u0026#34;A\u0026#34; in 80..89 -\u0026gt; \u0026#34;B\u0026#34; in 70..79 -\u0026gt; \u0026#34;C\u0026#34; in 60..69 -\u0026gt; \u0026#34;D\u0026#34; in 0..59 -\u0026gt; \u0026#34;F\u0026#34; else -\u0026gt; \u0026#34;Nota invalida\u0026#34; } println(\u0026#34;Nota $nota = $classificacao\u0026#34;) // when com verificacao de tipo (is) val valor: Any = \u0026#34;Kotlin Brasil\u0026#34; when (valor) { is String -\u0026gt; println(\u0026#34;É uma String com ${valor.length} caracteres\u0026#34;) is Int -\u0026gt; println(\u0026#34;É um inteiro: $valor\u0026#34;) is Boolean -\u0026gt; println(\u0026#34;É um booleano: $valor\u0026#34;) else -\u0026gt; println(\u0026#34;Tipo desconhecido\u0026#34;) } } Observe como o when é mais poderoso que o switch tradicional. Ele não precisa de break em cada caso (não há fall-through), suporta ranges com in, verificação de tipo com is (incluindo smart cast automático), e pode agrupar múltiplos valores com vírgula. Quando usado como expressão, o ramo else é obrigatório, a menos que o compilador possa garantir que todos os casos possíveis estão cobertos.\nWhen sem Argumento e Condições Complexas O when pode ser usado sem argumento, funcionando como uma sequência de if-else if mais elegante. Nesse formato, cada ramo contém uma condição booleana independente.\nfun main() { val temperatura = 32 val umidade = 75 // when sem argumento — como if-else if mais limpo val recomendacao = when { temperatura \u0026gt; 35 \u0026amp;\u0026amp; umidade \u0026gt; 80 -\u0026gt; \u0026#34;Calor extremo! Evite atividades ao ar livre.\u0026#34; temperatura \u0026gt; 30 -\u0026gt; \u0026#34;Está quente. Beba bastante água.\u0026#34; temperatura in 20..30 -\u0026gt; \u0026#34;Temperatura agradável para atividades externas.\u0026#34; temperatura in 10..19 -\u0026gt; \u0026#34;Está fresco. Leve um casaco.\u0026#34; temperatura \u0026lt; 10 -\u0026gt; \u0026#34;Está frio! Vista-se bem.\u0026#34; else -\u0026gt; \u0026#34;Condição nao prevista.\u0026#34; } println(\u0026#34;Temperatura: ${temperatura}°C — $recomendacao\u0026#34;) // when com blocos de codigo val numero = -5 when { numero \u0026gt; 0 -\u0026gt; { println(\u0026#34;$numero é positivo\u0026#34;) println(\u0026#34;Seu dobro é ${numero * 2}\u0026#34;) } numero \u0026lt; 0 -\u0026gt; { println(\u0026#34;$numero é negativo\u0026#34;) println(\u0026#34;Seu valor absoluto é ${-numero}\u0026#34;) } else -\u0026gt; { println(\u0026#34;$numero é zero\u0026#34;) } } // when em funcao de classificação val imc = 24.5 val classificacaoIMC = when { imc \u0026lt; 18.5 -\u0026gt; \u0026#34;Abaixo do peso\u0026#34; imc \u0026lt; 25.0 -\u0026gt; \u0026#34;Peso normal\u0026#34; imc \u0026lt; 30.0 -\u0026gt; \u0026#34;Sobrepeso\u0026#34; imc \u0026lt; 35.0 -\u0026gt; \u0026#34;Obesidade grau I\u0026#34; imc \u0026lt; 40.0 -\u0026gt; \u0026#34;Obesidade grau II\u0026#34; else -\u0026gt; \u0026#34;Obesidade grau III\u0026#34; } println(\u0026#34;IMC: $imc — Classificação: $classificacaoIMC\u0026#34;) } Essa forma do when sem argumento é particularmente útil quando as condições envolvem variáveis diferentes ou expressões complexas que não se encaixam naturalmente em um when com argumento. Ela torna cadeias longas de if-else if muito mais legíveis e organizadas.\nWhen com Sealed Classes e Enums O when tem uma integração especial com sealed classes e enums. Quando todos os subtipos possíveis são cobertos, o compilador não exige o ramo else, pois sabe que todas as possibilidades estão contempladas. Esse recurso é extremamente valioso para garantir que você não esqueceu de tratar algum caso.\nVeremos esse tópico em detalhes no tutorial de Sealed Classes, mas é importante saber desde já que essa combinação é uma das ferramentas mais poderosas do Kotlin para escrever código seguro e expressivo.\nComparação entre Estruturas Condicionais Para escolher a melhor estrutura condicional para cada situação, considere as seguintes orientações. Use if simples quando há apenas uma condição a verificar, ou quando você precisa de uma lógica verdadeiro/falso direta. Use if-else como expressão quando precisa atribuir um valor com base em uma condição binária, substituindo o operador ternário. Use when com argumento quando precisa comparar uma variável contra múltiplos valores possíveis, e use when sem argumento quando tem múltiplas condições independentes que não se relacionam a uma única variável.\nO when é geralmente preferível a cadeias longas de if-else if porque é mais legível, menos propenso a erros e mais fácil de manter. A regra geral é: se você tem mais de dois ramos condicionais, considere usar when.\nDicas e Erros Comuns Ao trabalhar com estruturas condicionais em Kotlin, evite estes erros frequentes:\nEsquecer o else quando when é usado como expressão: se você está atribuindo o resultado de um when a uma variável, precisa de um ramo else (exceto com sealed classes/enums exaustivos). Sem ele, o compilador não tem garantia de que sempre haverá um valor.\nUsar if encadeado onde when seria mais claro: cadeias de if-else if com mais de três condições ficam muito mais legíveis como when. Refatore sempre que possível.\nNão aproveitar o when como expressão: muitos desenvolvedores vindos de Java usam when apenas como statement e depois atribuem o valor manualmente. Use-o como expressão diretamente.\nEsquecer que in funciona com ranges no when: em vez de escrever valor \u0026gt;= 10 \u0026amp;\u0026amp; valor \u0026lt;= 20, use valor in 10..20 para código mais idiomático e legível.\nNão usar smart cast após verificação is: depois de verificar o tipo com is dentro de um when, o compilador já faz o cast automaticamente. Não faça cast manual desnecessário.\nUsar comparação com true ou false: escreva if (ativo) em vez de if (ativo == true). A segunda forma é redundante e considerada não-idiomática em Kotlin.\nConclusão e Próximos Passos As estruturas condicionais em Kotlin são mais expressivas e seguras do que em muitas outras linguagens. O uso de if e when como expressões é um dos recursos que tornam o código Kotlin mais conciso e elegante, eliminando variáveis temporárias e reduzindo a chance de erros. A integração do when com o sistema de tipos, especialmente com sealed classes e smart casts, é uma ferramenta poderosa que você vai usar constantemente.\nPara continuar aprendendo, recomendo os próximos tutoriais:\nLoops: For, While e Do-While — domine as estruturas de repetição Funções em Kotlin — aprenda a criar funções reutilizáveis Sealed Classes Passo a Passo — veja o when brilhar com sealed classes Pratique criando programas que usem when com diferentes tipos de condições. Um bom exercício é criar um conversor de unidades ou uma calculadora que use when para selecionar operações. Quanto mais você praticar, mais natural será escolher a estrutura condicional certa para cada situação.\n","permalink":"https://kotlin.dev.br/tutoriais/estruturas-condicionais/","summary":"\u003cp\u003eNeste tutorial, vamos explorar as estruturas condicionais do Kotlin, incluindo \u003ccode\u003eif\u003c/code\u003e, \u003ccode\u003ewhen\u003c/code\u003e e como elas funcionam como expressões que retornam valores. Você vai aprender a controlar o fluxo do seu programa de forma clara, concisa e idiomática, aproveitando recursos exclusivos que Kotlin oferece em relação a outras linguagens.\u003c/p\u003e\n\u003ch2 id=\"o-if-como-expressão\"\u003eO if como Expressão\u003c/h2\u003e\n\u003cp\u003eEm Kotlin, o \u003ccode\u003eif\u003c/code\u003e funciona de duas formas: como instrução tradicional (statement) e como expressão que retorna um valor. Essa segunda forma é extremamente poderosa e elimina a necessidade do operador ternário que existe em Java e outras linguagens.\u003c/p\u003e","title":"If, When e Estruturas Condicionais em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Neste tutorial, você vai aprender tudo sobre lambdas em Kotlin: desde a sintaxe básica até conceitos avançados como closures, function references e funções inline. Lambdas são um dos recursos mais poderosos da linguagem e estão presentes em praticamente todo código Kotlin moderno. Ao final deste guia, você vai dominar programação funcional em Kotlin e saberá usar as principais funções da standard library como let, run, with, apply e also.\nO que São Lambdas? Uma lambda é, essencialmente, uma função anônima — uma função sem nome que pode ser tratada como um valor. Em Kotlin, lambdas são cidadãs de primeira classe, o que significa que você pode armazená-las em variáveis, passá-las como argumento para outras funções e retorná-las de funções.\nSe você já trabalhou com JavaScript, Python ou qualquer linguagem que suporte programação funcional, o conceito será familiar. A diferença é que Kotlin oferece uma sintaxe especialmente elegante para trabalhar com lambdas.\nSintaxe Básica de Lambdas A sintaxe de uma lambda em Kotlin segue este formato:\nval minhaLambda: (Int, Int) -\u0026gt; Int = { a, b -\u0026gt; a + b } // Chamando a lambda val resultado = minhaLambda(3, 5) // resultado = 8 println(resultado) Observe os elementos: as chaves {} delimitam o corpo da lambda, os parâmetros ficam antes da seta -\u0026gt;, e o último valor da expressão é o retorno implícito. Não é necessário usar a palavra return dentro de uma lambda.\nQuando a lambda tem apenas um parâmetro, Kotlin permite usar a palavra reservada it no lugar do nome do parâmetro:\nval dobrar: (Int) -\u0026gt; Int = { it * 2 } println(dobrar(7)) // 14 O uso de it é extremamente comum no dia a dia e torna o código mais conciso. No entanto, quando a lambda é complexa ou aninhada, é recomendável nomear o parâmetro explicitamente para manter a legibilidade.\nHigher-Order Functions Uma higher-order function é uma função que recebe outra função como parâmetro ou que retorna uma função. Em Kotlin, isso é natural graças ao suporte a lambdas.\nfun operacao(a: Int, b: Int, op: (Int, Int) -\u0026gt; Int): Int { return op(a, b) } // Usando com lambdas diferentes val soma = operacao(10, 5) { a, b -\u0026gt; a + b } // 15 val subtracao = operacao(10, 5) { a, b -\u0026gt; a - b } // 5 val produto = operacao(10, 5) { a, b -\u0026gt; a * b } // 50 println(\u0026#34;Soma: $soma, Subtração: $subtracao, Produto: $produto\u0026#34;) Note que quando a lambda é o último parâmetro de uma função, podemos movê-la para fora dos parênteses. Essa é a chamada trailing lambda syntax e é uma das convenções mais usadas em Kotlin.\nClosures Lambdas em Kotlin podem acessar e modificar variáveis do escopo externo — isso é o que chamamos de closure. Diferente de Java (onde variáveis capturadas precisam ser efetivamente final), em Kotlin a lambda pode alterar variáveis mutáveis do escopo:\nfun contadorDeCliques(): () -\u0026gt; Int { var cliques = 0 return { cliques++ cliques } } val contador = contadorDeCliques() println(contador()) // 1 println(contador()) // 2 println(contador()) // 3 A lambda \u0026ldquo;captura\u0026rdquo; a variável cliques e mantém uma referência a ela mesmo após a função contadorDeCliques ter retornado. Closures são muito úteis para criar funções com estado interno.\nFunction References (::) Além de lambdas, Kotlin permite passar referências a funções já existentes usando o operador ::. Isso é chamado de function reference:\nfun ehPar(numero: Int): Boolean = numero % 2 == 0 val numeros = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // Usando function reference em vez de lambda val pares = numeros.filter(::ehPar) println(pares) // [2, 4, 6, 8, 10] // Equivalente com lambda: val paresLambda = numeros.filter { it % 2 == 0 } Você também pode referenciar métodos de uma classe ou construtores:\ndata class Usuario(val nome: String, val idade: Int) val nomes = listOf(\u0026#34;Ana\u0026#34;, \u0026#34;Bruno\u0026#34;, \u0026#34;Carla\u0026#34;) // Referência ao construtor val usuarios = nomes.map { Usuario(it, 25) } // Referência a metodo de instância val tamanhos = nomes.map(String::length) println(tamanhos) // [3, 5, 5] Funções Inline Quando usamos higher-order functions com lambdas, cada lambda cria um objeto em memória. Para evitar esse overhead, Kotlin oferece a palavra-chave inline:\ninline fun medirTempo(bloco: () -\u0026gt; Unit) { val inicio = System.currentTimeMillis() bloco() val fim = System.currentTimeMillis() println(\u0026#34;Executado em ${fim - inicio}ms\u0026#34;) } medirTempo { // Código a ser medido val lista = (1..1_000_000).toList().shuffled().sorted() println(\u0026#34;Lista ordenada com ${lista.size} elementos\u0026#34;) } Funções inline substituem a chamada da lambda pelo seu corpo diretamente no local de chamada durante a compilação. Isso elimina a criação de objetos e melhora a performance, especialmente em loops e código crítico.\nLambdas da Standard Library Kotlin oferece um conjunto de funções de escopo extremamente úteis que usam lambdas. Vamos explorar cada uma delas:\nlet Usada para executar um bloco de código com um objeto como argumento. Muito comum para null checks:\nval nome: String? = \u0026#34;Kotlin Brasil\u0026#34; nome?.let { println(\u0026#34;O nome tem ${it.length} caracteres\u0026#34;) println(\u0026#34;Em maiúsculas: ${it.uppercase()}\u0026#34;) } // Se nome for null, o bloco nao é executado run Similar ao let, mas o objeto é acessado via this em vez de it:\nval resultado = \u0026#34;Kotlin\u0026#34;.run { println(\u0026#34;O texto é: $this\u0026#34;) length // retorno implícito } println(\u0026#34;Tamanho: $resultado\u0026#34;) // 6 with Igual ao run, mas o objeto é passado como argumento em vez de ser o receiver:\nval builder = StringBuilder() with(builder) { append(\u0026#34;Kotlin \u0026#34;) append(\u0026#34;é \u0026#34;) append(\u0026#34;incrível!\u0026#34;) } println(builder.toString()) // Kotlin é incrível! apply Configura um objeto e retorna o próprio objeto. Ideal para inicialização:\nval usuario = Usuario(\u0026#34;Ana\u0026#34;, 28).apply { // Imagine que Usuario e uma classe com propriedades mutáveis println(\u0026#34;Criando usuário: $nome\u0026#34;) } also Executa uma ação adicional e retorna o objeto original. Útil para logging e debugging:\nval numeros = mutableListOf(1, 2, 3) .also { println(\u0026#34;Lista original: $it\u0026#34;) } .apply { add(4) } .also { println(\u0026#34;Após adicionar: $it\u0026#34;) } Exemplo Prático Completo Vamos combinar tudo em um exemplo realista — um mini sistema de filtro de produtos:\ndata class Produto(val nome: String, val preco: Double, val categoria: String) fun List\u0026lt;Produto\u0026gt;.filtrarE( vararg filtros: (Produto) -\u0026gt; Boolean ): List\u0026lt;Produto\u0026gt; { return this.filter { produto -\u0026gt; filtros.all { filtro -\u0026gt; filtro(produto) } } } fun main() { val produtos = listOf( Produto(\u0026#34;Notebook\u0026#34;, 3500.0, \u0026#34;Eletrônicos\u0026#34;), Produto(\u0026#34;Camiseta\u0026#34;, 79.90, \u0026#34;Roupas\u0026#34;), Produto(\u0026#34;Smartphone\u0026#34;, 2200.0, \u0026#34;Eletrônicos\u0026#34;), Produto(\u0026#34;Calça Jeans\u0026#34;, 150.0, \u0026#34;Roupas\u0026#34;), Produto(\u0026#34;Fone Bluetooth\u0026#34;, 199.90, \u0026#34;Eletrônicos\u0026#34;) ) val resultado = produtos .filtrarE( { it.categoria == \u0026#34;Eletrônicos\u0026#34; }, { it.preco \u0026lt; 3000.0 } ) .sortedBy { it.preco } .also { println(\u0026#34;Encontrados ${it.size} produtos\u0026#34;) } resultado.forEach { produto -\u0026gt; println(\u0026#34;${produto.nome} — R$ ${\u0026#34;%.2f\u0026#34;.format(produto.preco)}\u0026#34;) } } Erros Comuns Confundir it em lambdas aninhadas: quando você tem lambdas dentro de lambdas, cada uma tem seu próprio it. Nomeie os parâmetros explicitamente para evitar ambiguidade.\nEsquecer que o último valor é o retorno: em Kotlin, a última expressão de uma lambda é o retorno implícito. Não use return dentro de lambdas a menos que queira fazer um non-local return (que retorna da função externa).\nUsar inline desnecessariamente: marcar funções como inline é útil apenas quando elas recebem lambdas como parâmetro. Usar inline em funções comuns pode aumentar o tamanho do bytecode sem benefício.\nNão entender a diferença entre scope functions: let usa it, run/with/apply usam this, e apply/also retornam o objeto original enquanto let/run/with retornam o resultado da lambda.\nCapturar variáveis mutáveis em closures sem cuidado: embora Kotlin permita, alterar variáveis externas dentro de lambdas pode gerar bugs difíceis de rastrear, especialmente em código assíncrono com coroutines.\nConclusão e Próximos Passos Lambdas são o coração da programação funcional em Kotlin. Neste tutorial, você aprendeu a sintaxe básica, como usar it, closures, function references com ::, funções inline e as cinco scope functions da standard library. Com esse conhecimento, você está preparado para escrever código Kotlin idiomático e conciso.\nPara continuar sua jornada, recomendamos explorar os seguintes tópicos:\nExtension Functions para criar funções mais expressivas Generics para trabalhar com tipos parametrizados em lambdas Collections e suas operações funcionais avançadas como fold, reduce e groupBy Coroutines para usar lambdas em programação assíncrona Pratique criando suas próprias higher-order functions e experimentando as scope functions no seu código diário. Quanto mais você usar lambdas, mais natural a sintaxe vai se tornar.\n","permalink":"https://kotlin.dev.br/tutoriais/lambdas-kotlin/","summary":"\u003cp\u003eNeste tutorial, você vai aprender tudo sobre \u003cstrong\u003elambdas em Kotlin\u003c/strong\u003e: desde a sintaxe básica até conceitos avançados como closures, function references e funções inline. Lambdas são um dos recursos mais poderosos da linguagem e estão presentes em praticamente todo código Kotlin moderno. Ao final deste guia, você vai dominar programação funcional em Kotlin e saberá usar as principais funções da standard library como \u003ccode\u003elet\u003c/code\u003e, \u003ccode\u003erun\u003c/code\u003e, \u003ccode\u003ewith\u003c/code\u003e, \u003ccode\u003eapply\u003c/code\u003e e \u003ccode\u003ealso\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"o-que-são-lambdas\"\u003eO que São Lambdas?\u003c/h2\u003e\n\u003cp\u003eUma \u003ca href=\"/glossario/lambda/\"\u003elambda\u003c/a\u003e é, essencialmente, uma função anônima — uma função sem nome que pode ser tratada como um valor. Em Kotlin, lambdas são cidadãs de primeira classe, o que significa que você pode armazená-las em variáveis, passá-las como argumento para outras funções e retorná-las de funções.\u003c/p\u003e","title":"Lambdas em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Neste tutorial, vamos explorar o sistema de collections do Kotlin de forma completa e prática. Collections (coleções) são estruturas de dados fundamentais em qualquer linguagem de programação, é o Kotlin oferece uma API rica e expressiva para trabalhar com listas, conjuntos e mapas. Você aprenderá a diferença entre coleções mutáveis e imutáveis, as operações mais comuns como filter, map, flatMap e groupBy, além de sequences para processamento eficiente e collection builders para construção flexível.\nList: Coleções Ordenadas List é uma coleção ordenada que permite elementos duplicados. Em Kotlin, listOf() cria uma lista imutável (somente leitura), enquanto mutableListOf() cria uma lista que pode ser modificada.\nfun main() { // Lista imutável val linguagens = listOf(\u0026#34;Kotlin\u0026#34;, \u0026#34;Java\u0026#34;, \u0026#34;Python\u0026#34;, \u0026#34;Kotlin\u0026#34;) // duplicatas OK println(linguagens) // [Kotlin, Java, Python, Kotlin] println(linguagens[0]) // Kotlin println(linguagens.size) // 4 println(linguagens.contains(\u0026#34;Java\u0026#34;)) // true println(\u0026#34;Python\u0026#34; in linguagens) // true (operador \u0026#39;in\u0026#39;) // Lista mutável val tarefas = mutableListOf(\u0026#34;Estudar\u0026#34;, \u0026#34;Codar\u0026#34;) tarefas.add(\u0026#34;Testar\u0026#34;) tarefas.add(1, \u0026#34;Planejar\u0026#34;) // Insere na posição 1 tarefas.removeAt(0) // Remove \u0026#34;Estudar\u0026#34; tarefas[0] = \u0026#34;Arquitetar\u0026#34; // Substitui \u0026#34;Planejar\u0026#34; println(tarefas) // [Arquitetar, Codar, Testar] // Conversao entre mutável e imutável val imutavel: List\u0026lt;String\u0026gt; = tarefas.toList() val mutavel: MutableList\u0026lt;String\u0026gt; = linguagens.toMutableList() // Lista tipada vazia val vazia = emptyList\u0026lt;Int\u0026gt;() val vaziaComTipo: List\u0026lt;String\u0026gt; = listOf() println(vazia.isEmpty()) // true } A distinção entre List (somente leitura) e MutableList é uma escolha de design do Kotlin que promove imutabilidade. Quando você passa uma List para uma função, quem recebe tem a garantia de que a lista não será modificada por aquela referência, tornando o código mais previsível.\nSet: Coleções sem Duplicatas Set é uma coleção que não permite elementos duplicados. setOf() cria um set imutável e mutableSetOf() cria um set mutável. A implementação padrão mantém a ordem de inserção (LinkedHashSet).\nfun main() { val frutas = setOf(\u0026#34;Maçã\u0026#34;, \u0026#34;Banana\u0026#34;, \u0026#34;Maçã\u0026#34;, \u0026#34;Laranja\u0026#34;) println(frutas) // [Maçã, Banana, Laranja] — sem duplicata println(frutas.size) // 3 // Operações de conjunto val frutasA = setOf(\u0026#34;Maçã\u0026#34;, \u0026#34;Banana\u0026#34;, \u0026#34;Laranja\u0026#34;) val frutasB = setOf(\u0026#34;Banana\u0026#34;, \u0026#34;Uva\u0026#34;, \u0026#34;Morango\u0026#34;) println(frutasA union frutasB) // [Maçã, Banana, Laranja, Uva, Morango] println(frutasA intersect frutasB) // [Banana] println(frutasA subtract frutasB) // [Maçã, Laranja] // Set mutável val tags = mutableSetOf(\u0026#34;kotlin\u0026#34;, \u0026#34;android\u0026#34;) tags.add(\u0026#34;kotlin\u0026#34;) // Não adiciona (já existe) tags.add(\u0026#34;jetpack\u0026#34;) println(tags) // [kotlin, android, jetpack] // Remover duplicatas de uma lista val comDuplicatas = listOf(1, 2, 3, 2, 1, 4, 3, 5) val semDuplicatas = comDuplicatas.toSet().toList() println(semDuplicatas) // [1, 2, 3, 4, 5] // distinct() e um atalho println(comDuplicatas.distinct()) // [1, 2, 3, 4, 5] } Sets são ideais para verificações de pertencimento (operação in) e para garantir unicidade. A busca em um HashSet tem complexidade O(1), muito mais eficiente do que buscar em uma lista.\nMap: Coleções de Chave-Valor Map armazena pares de chave-valor, onde cada chave é única. mapOf() cria um map imutável e mutableMapOf() cria um map mutável.\nfun main() { // Map imutável val capitais = mapOf( \u0026#34;Brasil\u0026#34; to \u0026#34;Brasília\u0026#34;, \u0026#34;Argentina\u0026#34; to \u0026#34;Buenos Aires\u0026#34;, \u0026#34;Chile\u0026#34; to \u0026#34;Santiago\u0026#34; ) println(capitais[\u0026#34;Brasil\u0026#34;]) // Brasília println(capitais[\u0026#34;Portugal\u0026#34;]) // null (chave nao existe) println(capitais.getOrDefault(\u0026#34;Portugal\u0026#34;, \u0026#34;Desconhecida\u0026#34;)) // Desconhecida // Iteração for ((pais, capital) in capitais) { println(\u0026#34;$pais → $capital\u0026#34;) } // Map mutável val estoque = mutableMapOf( \u0026#34;Camiseta\u0026#34; to 50, \u0026#34;Calça\u0026#34; to 30 ) estoque[\u0026#34;Tênis\u0026#34;] = 20 // Adiciona novo par estoque[\u0026#34;Camiseta\u0026#34;] = 45 // Atualiza valor existente estoque.remove(\u0026#34;Calça\u0026#34;) // Remove par println(estoque) // {Camiseta=45, Tênis=20} // getOrPut: retorna o valor existente ou insere e retorna o novo val cache = mutableMapOf\u0026lt;String, Int\u0026gt;() val valor = cache.getOrPut(\u0026#34;chave\u0026#34;) { println(\u0026#34;Calculando...\u0026#34;) 42 } println(valor) // 42 (calculou e inseriu) println(cache.getOrPut(\u0026#34;chave\u0026#34;) { 100 }) // 42 (já existia, nao recalcula) // Verificações println(\u0026#34;Camiseta\u0026#34; in estoque) // true (verifica chave) println(estoque.containsValue(20)) // true (verifica valor) } O operador to é uma função infix que cria um Pair. A expressão \u0026quot;Brasil\u0026quot; to \u0026quot;Brasília\u0026quot; é equivalente a Pair(\u0026quot;Brasil\u0026quot;, \u0026quot;Brasília\u0026quot;). Maps são essenciais para caches, configurações e qualquer cenário de busca por chave.\nOperações Comuns: filter, map e flatMap O Kotlin oferece uma vasta coleção de funções de transformação inspiradas na programação funcional. Essas operações usam lambdas e retornam novas coleções, sem modificar a original.\ndata class Produto(val nome: String, val preco: Double, val categoria: String) fun main() { val produtos = listOf( Produto(\u0026#34;Notebook\u0026#34;, 4500.0, \u0026#34;Eletrônicos\u0026#34;), Produto(\u0026#34;Teclado\u0026#34;, 250.0, \u0026#34;Periféricos\u0026#34;), Produto(\u0026#34;Mouse\u0026#34;, 120.0, \u0026#34;Periféricos\u0026#34;), Produto(\u0026#34;Monitor\u0026#34;, 2200.0, \u0026#34;Eletrônicos\u0026#34;), Produto(\u0026#34;Cadeira\u0026#34;, 1800.0, \u0026#34;Móveis\u0026#34;), Produto(\u0026#34;Mesa\u0026#34;, 900.0, \u0026#34;Móveis\u0026#34;) ) // filter: seleciona elementos que atendem a condicao val caros = produtos.filter { it.preco \u0026gt; 1000 } println(\u0026#34;Caros: ${caros.map { it.nome }}\u0026#34;) // Caros: [Notebook, Monitor, Cadeira] // map: transforma cada elemento val nomes = produtos.map { it.nome.uppercase() } println(\u0026#34;Nomes: $nomes\u0026#34;) // Nomes: [NOTEBOOK, TECLADO, MOUSE, MONITOR, CADEIRA, MESA] // map com transformação complexa val resumos = produtos.map { \u0026#34;${it.nome}: R$${\u0026#34;%.2f\u0026#34;.format(it.preco)}\u0026#34; } println(resumos) // flatMap: transforma e achata listas aninhadas val categorias = listOf( listOf(\u0026#34;Kotlin\u0026#34;, \u0026#34;Java\u0026#34;), listOf(\u0026#34;Python\u0026#34;, \u0026#34;Ruby\u0026#34;), listOf(\u0026#34;Go\u0026#34;, \u0026#34;Rust\u0026#34;) ) val todasLinguagens = categorias.flatMap { it } println(todasLinguagens) // [Kotlin, Java, Python, Ruby, Go, Rust] // flatMap pratico: caracteres de cada nome val letras = produtos.flatMap { it.nome.toList() }.distinct() println(\u0026#34;Letras unicas: ${letras.size}\u0026#34;) // Encadeamento de operacoes val resultado = produtos .filter { it.preco \u0026lt; 2000 } .sortedByDescending { it.preco } .map { \u0026#34;${it.nome} (${it.categoria})\u0026#34; } println(\u0026#34;Resultado: $resultado\u0026#34;) // Resultado: [Cadeira (Móveis), Mesa (Móveis), Teclado (Periféricos), Mouse (Periféricos)] } O encadeamento de operações é uma das grandes forças do Kotlin. Cada operação retorna uma nova coleção, permitindo criar pipelines de transformação expressivos e legíveis.\nOperações Avançadas: groupBy e associate groupBy e associate são operações poderosas para reorganizar dados em mapas.\ndata class Aluno(val nome: String, val turma: String, val nota: Double) fun main() { val alunos = listOf( Aluno(\u0026#34;Ana\u0026#34;, \u0026#34;A\u0026#34;, 8.5), Aluno(\u0026#34;Bruno\u0026#34;, \u0026#34;B\u0026#34;, 7.0), Aluno(\u0026#34;Carla\u0026#34;, \u0026#34;A\u0026#34;, 9.2), Aluno(\u0026#34;Diego\u0026#34;, \u0026#34;B\u0026#34;, 6.5), Aluno(\u0026#34;Eva\u0026#34;, \u0026#34;A\u0026#34;, 7.8), Aluno(\u0026#34;Felipe\u0026#34;, \u0026#34;B\u0026#34;, 8.0) ) // groupBy: agrupa elementos por uma chave val porTurma: Map\u0026lt;String, List\u0026lt;Aluno\u0026gt;\u0026gt; = alunos.groupBy { it.turma } porTurma.forEach { (turma, lista) -\u0026gt; println(\u0026#34;Turma $turma: ${lista.map { it.nome }}\u0026#34;) } // Turma A: [Ana, Carla, Eva] // Turma B: [Bruno, Diego, Felipe] // Média por turma val mediaPorTurma = alunos.groupBy { it.turma } .mapValues { (_, alunosTurma) -\u0026gt; alunosTurma.map { it.nota }.average() } println(\u0026#34;Médias: $mediaPorTurma\u0026#34;) // Médias: {A=8.5, B=7.166666666666667} // associate: cria map a partir de transformação val notasPorNome: Map\u0026lt;String, Double\u0026gt; = alunos.associate { it.nome to it.nota } println(\u0026#34;Notas: $notasPorNome\u0026#34;) // Notas: {Ana=8.5, Bruno=7.0, Carla=9.2, Diego=6.5, Eva=7.8, Felipe=8.0} // associateBy: usa uma propriedade como chave val alunoPorNome: Map\u0026lt;String, Aluno\u0026gt; = alunos.associateBy { it.nome } println(alunoPorNome[\u0026#34;Carla\u0026#34;]) // Aluno(nome=Carla, turma=A, nota=9.2) // partition: divide em dois grupos (par de listas) val (aprovados, reprovados) = alunos.partition { it.nota \u0026gt;= 7.0 } println(\u0026#34;Aprovados: ${aprovados.map { it.nome }}\u0026#34;) // [Ana, Bruno, Carla, Eva, Felipe] println(\u0026#34;Reprovados: ${reprovados.map { it.nome }}\u0026#34;) // [Diego] // Outras operacoes uteis println(\u0026#34;Melhor nota: ${alunos.maxByOrNull { it.nota }?.nome}\u0026#34;) // Carla println(\u0026#34;Pior nota: ${alunos.minByOrNull { it.nota }?.nome}\u0026#34;) // Diego println(\u0026#34;Soma notas: ${alunos.sumOf { it.nota }}\u0026#34;) // 47.0 println(\u0026#34;Todos aprovados: ${alunos.all { it.nota \u0026gt;= 7.0 }}\u0026#34;) // false println(\u0026#34;Algum com 10: ${alunos.any { it.nota == 10.0 }}\u0026#34;) // false } Sequences: Processamento Lazy Por padrão, operações de coleção em Kotlin são eager — cada operação processa todos os elementos e cria uma coleção intermediária. Sequences processam elementos um a um (lazy), o que é mais eficiente para coleções grandes ou cadeias com muitas operações.\nfun main() { val numeros = (1..1_000_000).toList() // EAGER: cria lista intermediária a cada passo val resultadoEager = numeros .filter { it % 2 == 0 } // Cria lista com 500.000 elementos .map { it * 3 } // Cria outra lista com 500.000 elementos .take(5) // Pega apenas 5 (desperdiçou processamento!) println(resultadoEager) // [6, 12, 18, 24, 30] // LAZY (Sequence): processa elemento a elemento, para quando tem 5 val resultadoLazy = numeros.asSequence() .filter { it % 2 == 0 } .map { it * 3 } .take(5) .toList() // Terminal operation: dispara o processamento println(resultadoLazy) // [6, 12, 18, 24, 30] // Gerando sequences diretamente val fibonacci = generateSequence(Pair(0L, 1L)) { (a, b) -\u0026gt; Pair(b, a + b) } .map { it.first } .take(10) .toList() println(\u0026#34;Fibonacci: $fibonacci\u0026#34;) // Fibonacci: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] // sequence builder com yield val potenciasDeDois = sequence { var valor = 1 while (true) { yield(valor) valor *= 2 } } println(potenciasDeDois.take(10).toList()) // [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] } Use sequences quando tiver coleções grandes (milhares de elementos) ou cadeias longas de transformações. Para coleções pequenas, a diferença é negligível e coleções normais podem ser até mais rápidas devido ao overhead das sequences.\nCollection Builders Kotlin oferece funções builder para construir coleções de forma condicional e programática, mantendo a imutabilidade no resultado final.\nfun construirMenu(admin: Boolean, premium: Boolean): List\u0026lt;String\u0026gt; { return buildList { add(\u0026#34;Início\u0026#34;) add(\u0026#34;Perfil\u0026#34;) add(\u0026#34;Configurações\u0026#34;) if (premium) { add(\u0026#34;Conteúdo Exclusivo\u0026#34;) add(\u0026#34;Suporte Prioritário\u0026#34;) } if (admin) { addAll(listOf(\u0026#34;Painel Admin\u0026#34;, \u0026#34;Gerenciar Usuários\u0026#34;, \u0026#34;Relatórios\u0026#34;)) } add(\u0026#34;Sair\u0026#34;) } } fun construirConfiguracoes(params: Map\u0026lt;String, String\u0026gt;): Map\u0026lt;String, String\u0026gt; { return buildMap { put(\u0026#34;versao\u0026#34;, \u0026#34;1.0.0\u0026#34;) put(\u0026#34;ambiente\u0026#34;, \u0026#34;producao\u0026#34;) putAll(params) // Adiciona todas as configurações recebidas if (!containsKey(\u0026#34;timeout\u0026#34;)) { put(\u0026#34;timeout\u0026#34;, \u0026#34;30\u0026#34;) } } } fun main() { println(construirMenu(admin = false, premium = true)) // [Início, Perfil, Configurações, Conteúdo Exclusivo, Suporte Prioritário, Sair] println(construirMenu(admin = true, premium = false)) // [Início, Perfil, Configurações, Painel Admin, Gerenciar Usuários, Relatórios, Sair] val config = construirConfiguracoes(mapOf(\u0026#34;região\u0026#34; to \u0026#34;br\u0026#34;, \u0026#34;timeout\u0026#34; to \u0026#34;60\u0026#34;)) println(config) // {versao=1.0.0, ambiente=producao, região=br, timeout=60} } Collection builders como buildList, buildSet e buildMap foram introduzidos no Kotlin 1.6 como estáveis. Eles permitem construir coleções imutáveis com lógica condicional, algo que antes exigia criar uma coleção mutável e convertê-la depois.\nErros Comuns Confundir List e MutableList. Tentar adicionar elementos a uma List retornada por listOf() causa erro. Se precisar modificar, use toMutableList() ou declare diretamente como mutableListOf().\nModificar coleção durante iteração. Iterar sobre uma MutableList e remover elementos simultaneamente causa ConcurrentModificationException. Use removeIf, filter ou itere sobre uma cópia.\nval lista = mutableListOf(1, 2, 3, 4, 5) // ERRADO: for (item in lista) { if (item \u0026gt; 3) lista.remove(item) } lista.removeIf { it \u0026gt; 3 } // CORRETO Usar sequences para coleções pequenas. O overhead de sequences não compensa para listas com poucos elementos. Reserve-as para cenários com muitos dados ou cadeias longas de operações.\nIgnorar a diferença entre map e flatMap. Usar map quando a lambda retorna uma lista produz List\u0026lt;List\u0026lt;T\u0026gt;\u0026gt;. Se você quer achatar o resultado, use flatMap.\nConclusão e Próximos Passos Neste tutorial, você aprendeu a usar collections em Kotlin de forma completa: List, Set e Map com suas variantes mutáveis e imutáveis, operações de transformação como filter, map, flatMap, groupBy e associate, sequences para processamento lazy e collection builders para construção condicional.\nO domínio de collections é fundamental para qualquer desenvolvedor Kotlin, pois praticamente toda aplicação manipula coleções de dados. O próximo passo é explorar higher-order functions e lambdas em maior profundidade, além de coroutines para processamento assíncrono de coleções com Flow. Recomendamos também estudar destructuring para extrair dados de mapas e data classes de forma elegante. Com esse conhecimento de collections, você está preparado para escrever código Kotlin funcional, conciso e performático.\n","permalink":"https://kotlin.dev.br/tutoriais/collections-kotlin/","summary":"\u003cp\u003eNeste tutorial, vamos explorar o sistema de \u003ca href=\"/glossario/collections/\"\u003ecollections\u003c/a\u003e do Kotlin de forma completa e prática. Collections (coleções) são estruturas de dados fundamentais em qualquer linguagem de programação, é o Kotlin oferece uma API rica e expressiva para trabalhar com listas, conjuntos e mapas. Você aprenderá a diferença entre coleções mutáveis e imutáveis, as operações mais comuns como \u003ccode\u003efilter\u003c/code\u003e, \u003ccode\u003emap\u003c/code\u003e, \u003ccode\u003eflatMap\u003c/code\u003e e \u003ccode\u003egroupBy\u003c/code\u003e, além de sequences para processamento eficiente e collection builders para construção flexível.\u003c/p\u003e","title":"Collections em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Uma das discussoes mais quentes no mundo mobile e: desenvolvimento nativo com Kotlin ou cross-platform com Flutter? Essa escolha impacta diretamente a arquitetura, a performance e até a composição do time de desenvolvimento. Vamos analisar os dois lados com profundidade.\nO Que Estamos Comparando Antes de tudo, é importante esclarecer que estamos comparando abordagens diferentes. Kotlin é uma linguagem de programação usada nativamente no Android e, com o Kotlin Multiplatform, para compartilhar lógica entre plataformas. Flutter é um framework cross-platform do Google que usa Dart como linguagem e renderiza sua própria UI.\nSão filosofias distintas, e entender isso e fundamental para uma comparação justa.\nDesenvolvimento Nativo com Kotlin O desenvolvimento nativo com Kotlin significa usar Jetpack Compose para Android e, opcionalmente, Kotlin Multiplatform para compartilhar lógica com iOS.\n// Jetpack Compose - UI nativa Android @Composable fun UserProfile(user: User) { Column( modifier = Modifier .fillMaxWidth() .padding(16.dp) ) { Text( text = user.nome, style = MaterialTheme.typography.headlineMedium ) Spacer(modifier = Modifier.height(8.dp)) Text( text = user.email, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.secondary ) } } Vantagens do Kotlin Nativo Performance maxima: Sem camadas intermediarias entre seu código e o sistema operacional Acesso total as APIs: Qualquer recurso novo do Android esta disponivel imediatamente Ecossistema maduro: Bibliotecas como Retrofit, Room, Hilt e Navigation são extremamente bem mantidas IDE poderosa: Android Studio oferece ferramentas de debug, profiling e preview excepcionais Com Kotlin Multiplatform // Logica compartilhada com KMP class LoginViewModel( private val authRepository: AuthRepository ) : ViewModel() { private val _loginState = MutableStateFlow\u0026lt;LoginState\u0026gt;(LoginState.Idle) val loginState: StateFlow\u0026lt;LoginState\u0026gt; = _loginState.asStateFlow() fun login(email: String, senha: String) { viewModelScope.launch { _loginState.value = LoginState.Loading authRepository.login(email, senha) .onSuccess { user -\u0026gt; _loginState.value = LoginState.Success(user) } .onFailure { error -\u0026gt; _loginState.value = LoginState.Error(error.message) } } } } Com KMP, você compartilha a lógica de negocios, networking e data layer entre Android e iOS, mantendo a UI nativa em cada plataforma.\nDesenvolvimento com Flutter Flutter usa Dart e renderiza seus próprios widgets, criando uma experiência visual consistente entre plataformas.\nA abordagem do Flutter e diferente: em vez de usar componentes nativos do sistema operacional, ele desenha cada pixel na tela usando o engine Skia (e mais recentemente Impeller). Isso garante consistencia visual, mas pode criar uma experiência que não se sente totalmente nativa.\nVantagens do Flutter Uma única codebase para tudo: UI e lógica compartilhadas entre Android, iOS, web e desktop Hot reload rápido: Mudancas visuais aparecem quase instantaneamente durante o desenvolvimento Widgets ricos: Biblioteca extensa de componentes prontos Curva de aprendizado: Relativamente rápido para criar telas bonitas Desvantagens do Flutter Dart como linguagem: Menos popular e com ecossistema menor que Kotlin Tamanho do app: Apps Flutter tendem a ser maiores por incluir o engine de renderizacao Integração nativa: Acessar APIs nativas requer platform channels, que adicionam complexidade atualizações do OS: Novos recursos do Android ou iOS demoram mais para serem acessiveis Comparação Técnica Detalhada Performance Em benchmarks e uso real, Kotlin nativo supera Flutter em praticamente todos os cenários que envolvem:\nAnimacoes complexas com muitos elementos na tela manipulação intensiva de dados Acesso a hardware (camera, sensores, bluetooth) Tempo de inicialização do app // Kotlin - Acesso direto a APIs de camera class CameraManager(private val context: Context) { private lateinit var cameraProvider: ProcessCameraProvider suspend fun iniciarCamera(previewView: PreviewView) { cameraProvider = ProcessCameraProvider.getInstance(context).await() val preview = Preview.Builder() .setTargetAspectRatio(AspectRatio.RATIO_16_9) .build() .also { it.setSurfaceProvider(previewView.surfaceProvider) } val imageAnalyzer = ImageAnalysis.Builder() .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build() cameraProvider.bindToLifecycle( lifecycleOwner, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageAnalyzer ) } } No Kotlin, o acesso a camera e direto, sem camadas intermediarias. No Flutter, você dependeria de um plugin que faz a ponte entre Dart e o código nativo.\nTamanho do Time e Produtividade Este e um ponto onde Flutter pode ter vantagem em cenários específicos. Se você tem um time pequeno e precisa entregar para Android e iOS rapidamente, Flutter permite que um único desenvolvedor cuide de ambas as plataformas com uma única codebase.\nPorem, com Kotlin Multiplatform, você pode compartilhar entre 50% e 70% do código entre plataformas, mantendo a UI nativa. Isso exige conhecimento de SwiftUI para iOS, mas o resultado final tende a ser mais polido.\nEcossistema e Bibliotecas Kotlin se beneficia enormemente do ecossistema JVM. Bibliotecas como:\n// Exemplo de stack tipica Kotlin dependencies { // Networking implementation(\u0026#34;io.ktor:ktor-client-core:2.3.7\u0026#34;) implementation(\u0026#34;io.ktor:ktor-client-serialization:2.3.7\u0026#34;) // Injeção de dependencia implementation(\u0026#34;io.insert-koin:koin-core:3.5.3\u0026#34;) // Database implementation(\u0026#34;app.cash.sqldelight:runtime:2.0.1\u0026#34;) // Serializacao implementation(\u0026#34;org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2\u0026#34;) } Essas bibliotecas são mantidas por grandes empresas e comunidades, com atualizações frequentes e documentação extensa.\nMercado de Trabalho no Brasil No Brasil, o cenário e interessante. Vagas para desenvolvimento Android nativo com Kotlin continuam sendo a maioria no mercado mobile. Flutter cresceu bastante nos ultimos anos, especialmente em startups e empresas menores que precisam otimizar recursos.\nDados de plataformas de emprego mostram que:\nVagas Kotlin Android pagam em media 15-20% mais que vagas Flutter Ha mais vagas senior para Kotlin nativo Flutter tem crescido em vagas junior e pleno Empresas grandes (bancos, fintechs) preferem desenvolvimento nativo Quando Escolher Cada Abordagem Escolha Kotlin nativo (com ou sem KMP) quando:\nPerformance e prioridade maxima Você precisa de integração profunda com APIs do sistema O projeto e de longo prazo e precisa acompanhar atualizações do OS Você quer o maximo de controle sobre a experiência do usuário O time tem ou pode ter especialistas por plataforma Escolha Flutter quando:\nTime muito pequeno (1-2 devs) que precisa entregar para ambas as plataformas Prototipacao rápida e MVPs A experiência não precisa ser pixel-perfect nativa Consistencia visual entre plataformas e mais importante que aderencia nativa O Futuro: Compose Multiplatform Vale mencionar que o Compose Multiplatform esta mudando essa equacao. Com ele, você pode compartilhar até a UI entre plataformas usando Kotlin:\n// Compose Multiplatform - UI compartilhada @Composable fun App() { MaterialTheme { var contador by remember { mutableStateOf(0) } Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Text(\u0026#34;Contador: $contador\u0026#34;) Button(onClick = { contador++ }) { Text(\u0026#34;Incrementar\u0026#34;) } } } } Isso posiciona Kotlin como uma alternativa cada vez mais viável ao Flutter, com a vantagem de manter acesso direto as APIs nativas quando necessário.\nConclusão A escolha entre Kotlin e Flutter não e simples e depende do contexto do seu projeto. Se você busca a melhor experiência possível, performance maxima e longevidade, Kotlin nativo com KMP e a escolha mais solida. Se você precisa de velocidade de entrega com um time reduzido e aceita compromissos na experiência nativa, Flutter e uma opção válida.\nMinha recomendacao pessoal: invista em Kotlin. O ecossistema e mais robusto, as oportunidades são mais diversas (mobile, backend, multiplatform) e o Compose Multiplatform esta fechando rapidamente a lacuna que tornava Flutter atraente. Para o backend do seu app, considere combinar Kotlin com Go para microsserviços leves ou Python para APIs com IA integrada.\n","permalink":"https://kotlin.dev.br/blog/kotlin-vs-flutter/","summary":"\u003cp\u003eUma das discussoes mais quentes no mundo mobile e: desenvolvimento nativo com Kotlin ou cross-platform com Flutter? Essa escolha impacta diretamente a arquitetura, a performance e até a composição do time de desenvolvimento. Vamos analisar os dois lados com profundidade.\u003c/p\u003e\n\u003ch2 id=\"o-que-estamos-comparando\"\u003eO Que Estamos Comparando\u003c/h2\u003e\n\u003cp\u003eAntes de tudo, é importante esclarecer que estamos comparando abordagens diferentes. Kotlin é uma linguagem de programação usada nativamente no Android e, com o Kotlin Multiplatform, para compartilhar lógica entre plataformas. Flutter é um framework cross-platform do Google que usa Dart como linguagem e renderiza sua própria UI.\u003c/p\u003e","title":"Kotlin vs Flutter: Nativo ou Cross-Platform? | Kotlin Brasil"},{"content":"Neste tutorial, vamos explorar em profundidade o sistema de null safety do Kotlin, uma das funcionalidades mais importantes e inovadoras da linguagem. NullPointerException (NPE) é historicamente um dos erros mais comuns em Java e outras linguagens. O Kotlin resolve esse problema no nível do sistema de tipos, distinguindo entre referências que podem ser nulas e referências que nunca são nulas. Você vai aprender sobre tipos nullable, safe calls, Elvis operator, non-null assertion, funções como let e also, smart casts e platform types.\nTipos Nullable e Non-Nullable Em Kotlin, o sistema de tipos diferencia entre referências que podem conter null e referências que não podem. Por padrão, todos os tipos são non-nullable. Para permitir que uma variável contenha null, você adiciona ? ao tipo.\nfun main() { // Tipos non-nullable: NUNCA podem ser null var nome: String = \u0026#34;Kotlin Brasil\u0026#34; // nome = null // ERRO DE COMPILAÇÃO: Null can not be a value of a non-null type // Tipos nullable: podem ser null var sobrenome: String? = \u0026#34;Silva\u0026#34; sobrenome = null // OK — tipo permite null // Non-nullable é garantido pelo compilador println(nome.length) // Seguro: \u0026#39;nome\u0026#39; nunca é null // Nullable precisa de tratamento especial // println(sobrenome.length) // ERRO: Only safe (?.) or non-null asserted (!!) calls are allowed println(sobrenome?.length) // Seguro: retorna null se sobrenome for null } Essa distinção no sistema de tipos é verificada em tempo de compilação. Isso significa que a maioria dos NPEs é detectada antes mesmo do programa ser executado, o que representa uma enorme vantagem sobre linguagens como Java.\nSafe Calls (?.) O operador de safe call ?. permite acessar propriedades e chamar métodos em referências nullable de forma segura. Se a referência for null, a expressão inteira retorna null em vez de lançar uma exceção.\nfun obterComprimento(texto: String?): Int? { return texto?.length } fun main() { val nome: String? = \u0026#34;Karina Melo\u0026#34; val vazio: String? = null println(nome?.length) // 11 println(vazio?.length) // null (sem excecao) // Encadeamento de safe calls val endereco: String? = \u0026#34;Rua das Flores, 123\u0026#34; println(endereco?.uppercase()?.take(10)) // RUA DAS FL println(null as String?) // null (nenhum metodo e chamado) // Safe call com atribuição val lista: MutableList\u0026lt;String\u0026gt;? = mutableListOf(\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;) lista?.add(\u0026#34;c\u0026#34;) // Adiciona normalmente println(lista) // [a, b, c] val listaNula: MutableList\u0026lt;String\u0026gt;? = null listaNula?.add(\u0026#34;x\u0026#34;) // Não faz nada, nao lança excecao println(listaNula) // null } Safe calls são encadeáveis: a?.b?.c?.d retorna null se qualquer parte da cadeia for null. Isso é especialmente útil ao navegar objetos aninhados vindos de APIs ou bancos de dados, onde qualquer nível pode ser ausente.\nElvis Operator (?:) O Elvis operator ?: fornece um valor padrão quando a expressão à esquerda é null. O nome vem do fato de que o símbolo ?: de lado lembra o topete do cantor Elvis Presley.\nfun main() { val nome: String? = null val nomeExibicao = nome ?: \u0026#34;Usuário Anônimo\u0026#34; println(nomeExibicao) // Usuário Anônimo val email: String? = \u0026#34;karina@kotlin.com\u0026#34; val emailExibicao = email ?: \u0026#34;Não informado\u0026#34; println(emailExibicao) // karina@kotlin.com (email nao é null) // Combinando safe call com Elvis val texto: String? = null val comprimento = texto?.length ?: 0 println(\u0026#34;Comprimento: $comprimento\u0026#34;) // Comprimento: 0 // Elvis com throw para falhar rápido fun buscarUsuario(id: String): String? { return if (id == \u0026#34;1\u0026#34;) \u0026#34;Karina\u0026#34; else null } val usuario = buscarUsuario(\u0026#34;1\u0026#34;) ?: throw IllegalArgumentException(\u0026#34;Usuário nao encontrado\u0026#34;) println(usuario) // Karina // Elvis com return para retorno antecipado fun processarNome(nome: String?): String { val nomeValido = nome ?: return \u0026#34;Nome nao fornecido\u0026#34; return \u0026#34;Processando: ${nomeValido.uppercase()}\u0026#34; } println(processarNome(\u0026#34;Maria\u0026#34;)) // Processando: MARIA println(processarNome(null)) // Nome nao fornecido } O padrão valor?.operação ?: valorPadrao é extremamente idiomático em Kotlin e substitui boa parte das verificações if (x != null) que seriam necessárias em Java. O Elvis operator também pode ser usado com throw e return, o que permite padrões de falha rápida muito elegantes.\nNon-Null Assertion (!!) O operador !! converte um tipo nullable em non-nullable, lançando KotlinNullPointerException se o valor for null. Use com extrema cautela — ele é o único mecanismo em Kotlin que pode causar NPE intencionalmente.\nfun main() { val nome: String? = \u0026#34;Kotlin\u0026#34; val nomeDefinitivo: String = nome!! // OK: nome nao é null println(nomeDefinitivo.length) // 6 // PERIGO: isso lança NullPointerException // val nulo: String? = null // val boom: String = nulo!! // KotlinNullPointerException! // Caso de uso legítimo: quando voce tem certeza da logica val numeros = listOf(1, 2, 3, 4, 5) val encontrado: Int? = numeros.find { it \u0026gt; 3 } // Sabemos que existe pelo menos um numero \u0026gt; 3 println(encontrado!! * 10) // 40 } A recomendação é evitar !! sempre que possível. Na maioria dos casos, safe calls com Elvis operator ou verificações if são alternativas melhores. O !! deve ser reservado para situações onde você tem absoluta certeza de que o valor não é null e quer que uma falha nessa garantia seja um erro explícito.\nlet e also para Verificações de Null A função de escopo let é frequentemente combinada com safe call para executar um bloco de código apenas quando o valor não é null. Dentro do bloco, o valor é acessado como it e já é non-nullable.\nfun enviarEmail(destinatario: String) { println(\u0026#34;Email enviado para: $destinatario\u0026#34;) } fun main() { val email: String? = \u0026#34;usuario@email.com\u0026#34; val emailNulo: String? = null // let com safe call: executa somente se nao for null email?.let { println(\u0026#34;Email tem ${it.length} caracteres\u0026#34;) enviarEmail(it) } // Email tem 19 caracteres // Email enviado para: usuario@email.com emailNulo?.let { println(\u0026#34;Isso nunca será impresso\u0026#34;) } // also para efeitos colaterais mantendo a referência original val nomeProcessado = email?.also { println(\u0026#34;Validando email: $it\u0026#34;) }?.uppercase() println(nomeProcessado) // USUARIO@EMAIL.COM // Combinando let com Elvis para valor padrao val comprimento = email?.let { it.trim().length } ?: 0 println(\u0026#34;Comprimento: $comprimento\u0026#34;) // Comprimento: 19 // Múltiplas verificações com let aninhados val nome: String? = \u0026#34;Karina\u0026#34; val sobrenome: String? = \u0026#34;Melo\u0026#34; nome?.let { n -\u0026gt; sobrenome?.let { s -\u0026gt; println(\u0026#34;Nome completo: $n $s\u0026#34;) } } // Nome completo: Karina Melo } O padrão variavel?.let { ... } é mais idiomático do que if (variavel != null) quando o objetivo é executar uma ação lateral ou transformar o valor. Para verificações simples, if pode ser mais legível.\nSmart Casts O compilador do Kotlin é inteligente o suficiente para reconhecer verificações de null e automaticamente converter o tipo para non-nullable dentro do bloco correspondente. Isso é chamado de smart cast.\nfun processarValor(valor: Any?) { // Após verificacao com \u0026#39;is\u0026#39;, o compilador faz smart cast if (valor is String) { // Aqui \u0026#39;valor\u0026#39; já é tratado como String (non-nullable) println(\u0026#34;String de ${valor.length} caracteres: ${valor.uppercase()}\u0026#34;) } // Verificação de null tambem ativa smart cast if (valor != null) { // Aqui \u0026#39;valor\u0026#39; é Any (non-nullable) println(\u0026#34;Valor nao-nulo: $valor (tipo: ${valor::class.simpleName})\u0026#34;) } } fun obterComprimento(texto: String?): Int { // Smart cast com return antecipado if (texto == null) return 0 // Daqui em diante, \u0026#39;texto\u0026#39; é tratado como String (non-nullable) return texto.length } fun classificar(valor: Any?) { when (valor) { null -\u0026gt; println(\u0026#34;Valor nulo\u0026#34;) is Int -\u0026gt; println(\u0026#34;Inteiro: ${valor * 2}\u0026#34;) // smart cast para Int is String -\u0026gt; println(\u0026#34;Texto: ${valor.uppercase()}\u0026#34;) // smart cast para String is List\u0026lt;*\u0026gt; -\u0026gt; println(\u0026#34;Lista com ${valor.size} itens\u0026#34;) // smart cast para List else -\u0026gt; println(\u0026#34;Outro tipo: $valor\u0026#34;) } } fun main() { processarValor(\u0026#34;Kotlin Brasil\u0026#34;) processarValor(42) processarValor(null) println(obterComprimento(\u0026#34;Olá\u0026#34;)) // 3 println(obterComprimento(null)) // 0 classificar(\u0026#34;teste\u0026#34;) classificar(42) classificar(listOf(1, 2, 3)) classificar(null) } Smart casts funcionam com if, when, \u0026amp;\u0026amp; e ||. Eles tornam o código mais limpo, eliminando casts explícitos que seriam necessários em Java. Note que smart casts só funcionam em variáveis locais (val) ou propriedades val sem getter customizado.\nPlatform Types Quando você usa código Java a partir do Kotlin, os tipos vêm sem informação de nullability — o Java não distingue entre nullable e non-nullable. O Kotlin trata esses tipos como platform types, representados com ! na documentação (por exemplo, String!).\n// Exemplo conceitual: chamando codigo Java a partir do Kotlin // Se tivermos uma classe Java: // public class JavaUtil { // public static String getNome() { return null; } // pode retornar null! // } // Em Kotlin, o retorno seria String! (platform type) // val nome = JavaUtil.getNome() // tipo inferido: String! // RECOMENDAÇÃO: sempre declare o tipo explicitamente ao lidar com codigo Java // val nomeSeguro: String? = JavaUtil.getNome() // Seguro: trata como nullable // val nomePerigoso: String = JavaUtil.getNome() // Perigoso: pode causar NPE fun main() { // Exemplo pratico com collections do Java val mapa = java.util.HashMap\u0026lt;String, String\u0026gt;() mapa[\u0026#34;chave\u0026#34;] = \u0026#34;valor\u0026#34; // get() retorna String? em Kotlin (tratamento correto) val resultado: String? = mapa[\u0026#34;inexistente\u0026#34;] println(resultado ?: \u0026#34;Não encontrado\u0026#34;) // Não encontrado // Sempre trate retornos de APIs Java como nullable val propriedade: String? = System.getProperty(\u0026#34;minha.prop\u0026#34;) println(propriedade ?: \u0026#34;Propriedade nao definida\u0026#34;) } A regra de ouro ao trabalhar com interoperabilidade Java é: trate tudo como nullable até ter certeza do contrário. Anote seus tipos explicitamente em vez de depender da inferência quando os valores vêm de código Java.\nErros Comuns Uso excessivo de !!. Cada !! é um ponto potencial de NPE. Se você está usando muitos !! no seu código, provavelmente está ignorando a proposta do null safety. Prefira safe calls e Elvis operator.\nNão tratar platform types. Assumir que retornos de APIs Java são non-nullable sem verificação é uma das causas mais frequentes de NPE em projetos Kotlin.\nSmart cast em var. Smart casts não funcionam em propriedades var porque outra thread poderia alterar o valor entre a verificação e o uso. Use let ou crie uma variável local val.\nvar nome: String? = \u0026#34;Kotlin\u0026#34; // if (nome != null) println(nome.length) // PODE falhar com var nome?.let { println(it.length) } // Seguro Ignorar tipos de coleções nullable. List\u0026lt;String\u0026gt; e List\u0026lt;String?\u0026gt; são tipos diferentes. O primeiro garante que nenhum elemento é null; o segundo permite elementos null dentro da lista. List\u0026lt;String\u0026gt;? é uma lista que pode ser null, mas seus elementos não.\nConclusão e Próximos Passos Neste tutorial, você aprendeu o sistema completo de null safety do Kotlin: tipos nullable, safe calls, Elvis operator, non-null assertion, let/also, smart casts e platform types. Esses mecanismos trabalham juntos para praticamente eliminar NullPointerExceptions do seu código.\nO próximo passo é estudar collections em Kotlin, onde você aplicará null safety no contexto de listas, sets e maps. Recomendamos também explorar coroutines onde null safety é essencial para lidar com resultados assíncronos. Com domínio de null safety, você escreve código Kotlin significativamente mais seguro e confiável do que o equivalente em Java.\n","permalink":"https://kotlin.dev.br/tutoriais/null-safety-tutorial/","summary":"\u003cp\u003eNeste tutorial, vamos explorar em profundidade o sistema de null safety do Kotlin, uma das funcionalidades mais importantes e inovadoras da linguagem. NullPointerException (NPE) é historicamente um dos erros mais comuns em Java e outras linguagens. O Kotlin resolve esse problema no nível do sistema de tipos, distinguindo entre referências que podem ser nulas e referências que nunca são nulas. Você vai aprender sobre tipos \u003ca href=\"/glossario/nullable/\"\u003enullable\u003c/a\u003e, safe calls, Elvis operator, non-null assertion, funções como \u003ccode\u003elet\u003c/code\u003e e \u003ccode\u003ealso\u003c/code\u003e, smart casts e platform types.\u003c/p\u003e","title":"Null Safety em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Se você desenvolve para mobile, provavelmente já se deparou com a duvida: Kotlin ou Swift? Ambas são linguagens modernas, com tipagem forte e recursos avançados. Mas cada uma tem suas particularidades, e entender essas diferenças pode fazer toda a diferenca na hora de escolher a tecnologia certa para seu projeto.\nNeste artigo, vamos fazer uma comparação detalhada entre Kotlin e Swift, analisando sintaxe, performance, ecossistema e casos de uso. A ideia não e declarar uma vencedora, mas te dar informações suficientes para tomar a melhor decisao.\nOrigens e Proposito Kotlin foi criada pela JetBrains e lancada oficialmente em 2016. Desde 2019, é a linguagem preferida pelo Google para desenvolvimento Android. Ela roda na JVM, pode compilar para JavaScript e código nativo, e com o Kotlin Multiplatform, permite compartilhar lógica entre plataformas.\nSwift foi criada pela Apple e lancada em 2014 como substituta do Objective-C. E a linguagem padrão para desenvolvimento iOS, macOS, watchOS e tvOS. Assim como Kotlin, Swift foi projetada para ser segura, expressiva e moderna.\nComparação de Sintaxe Declaracao de Variaveis As duas linguagens são bastante parecidas na declaracao de variaveis:\n// Kotlin val nome: String = \u0026#34;Kotlin Brasil\u0026#34; // imutavel var contador: Int = 0 // mutavel Em Swift, a abordagem e similar:\n// Swift (para referência) // let nome: String = \u0026#34;Kotlin Brasil\u0026#34; // imutavel // var contador: Int = 0 // mutavel A principal diferenca aqui e o uso de val vs let para imutabilidade. Ambas incentivam fortemente o uso de valores imutáveis.\nNull Safety Tanto Kotlin quanto Swift tratam nulabilidade no sistema de tipos, o que é um grande avanco em relação a linguagens mais antigas.\n// Kotlin var nome: String? = null val tamanho = nome?.length ?: 0 // Elvis operator // Safe call chain val resultado = usuario?.endereco?.cidade?.nome Swift usa uma abordagem muito similar com optionals e optional chaining. A diferenca e mais sintatica do que conceitual. Kotlin tem o operador Elvis (?:), enquanto Swift usa ?? para o mesmo proposito.\nData Classes vs Structs Kotlin tem data classes, que geram automaticamente equals, hashCode, toString e copy:\n// Kotlin data class Usuario( val nome: String, val email: String, val idade: Int ) val user1 = Usuario(\u0026#34;Ana\u0026#34;, \u0026#34;ana@email.com\u0026#34;, 28) val user2 = user1.copy(nome = \u0026#34;Maria\u0026#34;) Swift usa structs com valor semantico por padrão, o que é uma abordagem diferente mas igualmente poderosa. Structs em Swift são value types, enquanto data classes em Kotlin são reference types.\nCoroutines vs Async/Await Uma das maiores diferenças esta no modelo de programação assíncrona.\n// Kotlin Coroutines suspend fun buscarUsuarios(): List\u0026lt;Usuario\u0026gt; { val usuarios = withContext(Dispatchers.IO) { api.getUsuarios() } return usuarios } // Lancamento de coroutine viewModelScope.launch { val usuarios = buscarUsuarios() _state.value = UiState.Success(usuarios) } Kotlin usa coroutines, que são extremamente flexiveis e permitem controle fino sobre contextos de execução, cancelamento e structured concurrency. Swift adotou async/await nativo a partir do Swift 5.5, com uma abordagem mais integrada a linguagem.\nA vantagem do Kotlin aqui e a maturidade do sistema de coroutines e a riqueza de operadores disponniveis no Flow para programação reativa.\nExtension Functions Ambas as linguagens suportam extension functions, permitindo adicionar funcionalidades a tipos existentes:\n// Kotlin fun String.capitalizeWords(): String { return split(\u0026#34; \u0026#34;).joinToString(\u0026#34; \u0026#34;) { word -\u0026gt; word.replaceFirstChar { it.uppercase() } } } val titulo = \u0026#34;kotlin vs swift\u0026#34;.capitalizeWords() // \u0026#34;Kotlin Vs Swift\u0026#34; A implementação e praticamente identica nas duas linguagens, o que mostra como Kotlin e Swift compartilham muitas ideias de design.\nEcossistema e Ferramentas Kotlin IDE principal: IntelliJ IDEA e Android Studio Build system: Gradle (com suporte a Kotlin DSL) Gerenciador de pacotes: Maven Central, Gradle Multiplataforma: Kotlin Multiplatform permite compartilhar código entre Android, iOS, web e desktop Backend: Spring Boot, Ktor, com grande ecossistema JVM Swift IDE principal: Xcode Build system: Swift Package Manager, CocoaPods Gerenciador de pacotes: Swift Package Manager Multiplataforma: Limitado ao ecossistema Apple (com exceções como Vapor para server-side) Backend: Vapor, com ecossistema menor para server-side Kotlin Multiplatform: O Diferencial O maior trunfo de Kotlin na comparação com Swift e o Kotlin Multiplatform (KMP). Com KMP, você pode:\n// Código compartilhado entre Android e iOS expect fun getPlatformName(): String // Implementacao Android actual fun getPlatformName(): String = \u0026#34;Android\u0026#34; // Implementacao iOS actual fun getPlatformName(): String = \u0026#34;iOS\u0026#34; Isso significa que você pode escrever a lógica de negocios uma única vez e compartilha-la entre todas as plataformas. A camada de UI pode ser nativa (Jetpack Compose no Android, SwiftUI no iOS) ou compartilhada com Compose Multiplatform.\n// Repository compartilhado class UserRepository(private val api: UserApi) { suspend fun getUsers(): Result\u0026lt;List\u0026lt;User\u0026gt;\u0026gt; { return try { val users = api.fetchUsers() Result.success(users) } catch (e: Exception) { Result.failure(e) } } } Performance Em termos de performance pura, ambas as linguagens são muito competentes:\nKotlin/JVM se beneficia das otimizações da JVM, incluindo JIT compilation Swift compila para código nativo com LLVM, oferecendo performance excelente Kotlin/Native (usado no KMP para iOS) compila para código nativo também, mas historicamente tem sido um pouco mais lento que Swift nativo Na prática, para a maioria das aplicações mobile, a diferenca de performance entre as duas e negligenciavel. O gargalo quase nunca esta na linguagem, mas sim em operações de I/O, rede e renderizacao.\nComunidade e Mercado de Trabalho Kotlin tem uma comunidade global muito ativa, impulsionada pelo ecossistema Android e pelo crescimento do Kotlin Multiplatform. No Brasil, a comunidade Kotlin esta em pleno crescimento, com eventos, meetups e cada vez mais vagas.\nSwift tem uma comunidade forte, especialmente nos Estados Unidos e Europa, onde o ecossistema Apple domina. No Brasil, o mercado iOS e menor que o Android, o que reflete na quantidade de vagas disponniveis.\nSegundo pesquisas recentes, desenvolvedores Kotlin tendem a ter acesso a mais oportunidades no mercado brasileiro, tanto para mobile quanto para backend (gracas ao ecossistema JVM).\nQuando Escolher Cada Uma Escolha Kotlin quando:\nVocê quer desenvolver para Android Precisa compartilhar código entre plataformas com KMP Quer aproveitar o ecossistema JVM para backend Busca mais oportunidades no mercado brasileiro Escolha Swift quando:\nSeu foco exclusivo e o ecossistema Apple Precisa de integração profunda com APIs nativas da Apple Trabalha em uma empresa que e Apple-first Conclusão Kotlin e Swift são duas linguagens excelentes, e a \u0026ldquo;melhor\u0026rdquo; depende inteiramente do seu contexto. Se você esta no ecossistema Android ou busca versatilidade multiplataforma, Kotlin e a escolha natural. Se seu foco e exclusivamente Apple, Swift e o caminho.\nO mais interessante e que, por serem tao similares em design, aprender uma facilita muito o aprendizado da outra. Muitos desenvolvedores mobile acabam trabalhando com ambas ao longo da carreira, e isso só agrega valor ao seu perfil profissional.\nPara quem esta comecando, minha recomendacao e: comece com Kotlin. O alcance e maior, as oportunidades são mais abundantes no Brasil, e com Kotlin Multiplatform, você consegue atingir o ecossistema Apple sem precisar dominar Swift desde o inicio. Se segurança de memória é importante pra você (como é para Swift), Rust leva esse conceito ao extremo e é outra linguagem que vale explorar.\n","permalink":"https://kotlin.dev.br/blog/kotlin-vs-swift/","summary":"\u003cp\u003eSe você desenvolve para mobile, provavelmente já se deparou com a duvida: Kotlin ou Swift? Ambas são linguagens modernas, com tipagem forte e recursos avançados. Mas cada uma tem suas particularidades, e entender essas diferenças pode fazer toda a diferenca na hora de escolher a tecnologia certa para seu projeto.\u003c/p\u003e\n\u003cp\u003eNeste artigo, vamos fazer uma comparação detalhada entre Kotlin e Swift, analisando sintaxe, performance, ecossistema e casos de uso. A ideia não e declarar uma vencedora, mas te dar informações suficientes para tomar a melhor decisao.\u003c/p\u003e","title":"Kotlin vs Swift: Comparação Completa para Devs Mobile | Kotlin Brasil"},{"content":"Neste tutorial, vamos explorar interfaces em Kotlin de forma completa e prática. Interfaces definem um contrato que classes devem seguir, sem impor uma hierarquia rígida de herança. Diferente de Java até a versão 7, as interfaces em Kotlin podem conter implementações padrão de métodos e até propriedades com acessores. Você aprenderá a declarar e implementar interfaces, usar default methods, definir properties em interfaces, trabalhar com herança múltipla de interfaces e aplicar interface delegation.\nDeclaração e Implementação Básica Uma interface é declarada com a palavra-chave interface e pode conter métodos abstratos (sem corpo) e métodos com implementação padrão. Uma classe implementa uma interface usando a mesma sintaxe de herança, com dois-pontos.\ninterface Autenticavel { fun autenticar(senha: String): Boolean fun obterIdentificador(): String } class UsuarioSistema( val nome: String, private val senhaHash: String ) : Autenticavel { override fun autenticar(senha: String): Boolean { return senha.hashCode().toString() == senhaHash } override fun obterIdentificador(): String { return \u0026#34;user-${nome.lowercase().replace(\u0026#34; \u0026#34;, \u0026#34;-\u0026#34;)}\u0026#34; } } fun realizarLogin(entidade: Autenticavel, senha: String) { if (entidade.autenticar(senha)) { println(\u0026#34;Login bem-sucedido: ${entidade.obterIdentificador()}\u0026#34;) } else { println(\u0026#34;Falha na autenticacao para: ${entidade.obterIdentificador()}\u0026#34;) } } fun main() { val usuario = UsuarioSistema(\u0026#34;Maria Souza\u0026#34;, \u0026#34;12345\u0026#34;.hashCode().toString()) realizarLogin(usuario, \u0026#34;12345\u0026#34;) // Login bem-sucedido: user-maria-souza realizarLogin(usuario, \u0026#34;errada\u0026#34;) // Falha na autenticacao para: user-maria-souza } Interfaces promovem o princípio de programar para uma abstração, não para uma implementação concreta. A função realizarLogin aceita qualquer objeto que implemente Autenticavel, seja um usuário, um serviço externo ou qualquer outra entidade.\nDefault Methods (Métodos com Implementação Padrão) Em Kotlin, interfaces podem fornecer implementações padrão para seus métodos. Classes que implementam a interface podem usar a implementação padrão ou sobrescrevê-la.\ninterface Logger { val prefixo: String get() = \u0026#34;LOG\u0026#34; fun log(mensagem: String) { println(\u0026#34;[${prefixo}] ${timestamp()}: $mensagem\u0026#34;) } fun erro(mensagem: String) { println(\u0026#34;[${prefixo}-ERRO] ${timestamp()}: $mensagem\u0026#34;) } fun debug(mensagem: String) { println(\u0026#34;[${prefixo}-DEBUG] ${timestamp()}: $mensagem\u0026#34;) } // Método privado auxiliar (Kotlin 1.4+) private fun timestamp(): String { return java.time.LocalTime.now().toString().substringBefore(\u0026#34;.\u0026#34;) } } class ServicoDeUsuarios : Logger { override val prefixo = \u0026#34;USUARIOS\u0026#34; fun criarUsuario(nome: String) { log(\u0026#34;Criando usuário: $nome\u0026#34;) // Lógica de criacao... log(\u0026#34;Usuário $nome criado com sucesso\u0026#34;) } fun excluirUsuario(nome: String) { log(\u0026#34;Tentando excluir: $nome\u0026#34;) erro(\u0026#34;Operação de exclusão nao implementada\u0026#34;) } } fun main() { val serviço = ServicoDeUsuarios() serviço.criarUsuario(\u0026#34;Carlos\u0026#34;) serviço.excluirUsuario(\u0026#34;Carlos\u0026#34;) } Default methods permitem que interfaces forneçam comportamento reutilizável sem forçar cada implementador a reescrever código idêntico. Isso é especialmente poderoso quando combinado com propriedades que as classes podem personalizar, como o prefixo no exemplo.\nProperties em Interfaces Interfaces em Kotlin podem declarar propriedades. Elas podem ser abstratas (sem valor) ou ter um getter padrão. Interfaces não podem manter estado (não têm backing field), mas podem definir acessores que calculam valores.\ninterface Dimensionavel { val largura: Double // abstrata: implementador deve fornecer val altura: Double // abstrata: implementador deve fornecer // Property com getter padrao (calculada) val area: Double get() = largura * altura val perimetro: Double get() = 2 * (largura + altura) val ehQuadrado: Boolean get() = largura == altura } class Retangulo( override val largura: Double, override val altura: Double ) : Dimensionavel class Quadrado(lado: Double) : Dimensionavel { override val largura = lado override val altura = lado } fun imprimirDimensoes(forma: Dimensionavel) { println(\u0026#34;Largura: ${forma.largura} | Altura: ${forma.altura}\u0026#34;) println(\u0026#34;Área: ${forma.area} | Perímetro: ${forma.perimetro}\u0026#34;) println(\u0026#34;É quadrado: ${forma.ehQuadrado}\u0026#34;) println() } fun main() { imprimirDimensoes(Retangulo(10.0, 5.0)) // Largura: 10.0 | Altura: 5.0 | Área: 50.0 | Perímetro: 30.0 | É quadrado: false imprimirDimensoes(Quadrado(7.0)) // Largura: 7.0 | Altura: 7.0 | Área: 49.0 | Perímetro: 28.0 | É quadrado: true } Observe que Retangulo não precisa de corpo algum — as propriedades da interface são satisfeitas pelo construtor primário com override. Isso mostra como Kotlin pode ser conciso sem perder expressividade.\nHerança Múltipla de Interfaces Uma classe em Kotlin pode implementar múltiplas interfaces. Quando duas interfaces fornecem implementação padrão para o mesmo método, a classe deve resolver a ambiguidade explicitamente.\ninterface Serializavel { fun serializar(): String fun formato(): String { return \u0026#34;JSON\u0026#34; } } interface Imprimivel { fun imprimir() { println(\u0026#34;Imprimindo documento...\u0026#34;) } fun formato(): String { return \u0026#34;PDF\u0026#34; } } class Relatorio( val titulo: String, val conteudo: String ) : Serializavel, Imprimivel { override fun serializar(): String { return \u0026#34;\u0026#34;\u0026#34;{\u0026#34;titulo\u0026#34;: \u0026#34;$titulo\u0026#34;, \u0026#34;conteudo\u0026#34;: \u0026#34;$conteudo\u0026#34;}\u0026#34;\u0026#34;\u0026#34; } // OBRIGATÓRIO: resolver ambiguidade do metodo \u0026#39;formato\u0026#39; override fun formato(): String { // Pode escolher um, combinar ambos, ou ter logica própria val formatoSerial = super\u0026lt;Serializavel\u0026gt;.formato() val formatoImpressao = super\u0026lt;Imprimivel\u0026gt;.formato() return \u0026#34;$formatoSerial / $formatoImpressao\u0026#34; } override fun imprimir() { super.imprimir() // Chama a implementacao padrao de Imprimivel println(\u0026#34;Relatório: $titulo\u0026#34;) } } fun main() { val relatorio = Relatorio(\u0026#34;Vendas Q1\u0026#34;, \u0026#34;Total: R$150.000\u0026#34;) println(relatorio.serializar()) // {\u0026#34;titulo\u0026#34;: \u0026#34;Vendas Q1\u0026#34;, \u0026#34;conteudo\u0026#34;: \u0026#34;Total: R$150.000\u0026#34;} relatorio.imprimir() // Imprimindo documento... // Relatório: Vendas Q1 println(\u0026#34;Formato: ${relatorio.formato()}\u0026#34;) // Formato: JSON / PDF } A sintaxe super\u0026lt;NomeDaInterface\u0026gt;.método() permite chamar especificamente a implementação padrão de uma interface quando há ambiguidade. O compilador obriga você a resolver o conflito, evitando o problema do \u0026ldquo;diamante\u0026rdquo; que pode ocorrer em linguagens com herança múltipla de classes.\nInterface Delegation (Delegação de Interface) A delegação é um padrão de design poderoso onde, em vez de implementar uma interface manualmente, você delega todas as chamadas para outro objeto. Kotlin suporta delegation nativamente com a palavra-chave by.\ninterface Repositorio\u0026lt;T\u0026gt; { fun salvar(item: T) fun buscar(id: String): T? fun listar(): List\u0026lt;T\u0026gt; fun remover(id: String): Boolean } class RepositorioEmMemoria\u0026lt;T\u0026gt; : Repositorio\u0026lt;T\u0026gt; { private val dados = mutableMapOf\u0026lt;String, T\u0026gt;() private var contador = 0 override fun salvar(item: T) { dados[\u0026#34;id-${++contador}\u0026#34;] = item } override fun buscar(id: String): T? = dados[id] override fun listar(): List\u0026lt;T\u0026gt; = dados.values.toList() override fun remover(id: String): Boolean = dados.remove(id) != null } // Delega para \u0026#39;repositorio\u0026#39; e adiciona logging class RepositorioComLog\u0026lt;T\u0026gt;( private val repositorio: Repositorio\u0026lt;T\u0026gt; ) : Repositorio\u0026lt;T\u0026gt; by repositorio { // Sobrescreve apenas os metodos que precisam de logging override fun salvar(item: T) { println(\u0026#34;[LOG] Salvando item: $item\u0026#34;) repositorio.salvar(item) println(\u0026#34;[LOG] Item salvo com sucesso\u0026#34;) } override fun remover(id: String): Boolean { println(\u0026#34;[LOG] Removendo item: $id\u0026#34;) val resultado = repositorio.remover(id) println(\u0026#34;[LOG] Remoção ${if (resultado) \u0026#34;bem-sucedida\u0026#34; else \u0026#34;falhou\u0026#34;}\u0026#34;) return resultado } // buscar() e listar() são delegados automaticamente } fun main() { val repo = RepositorioComLog(RepositorioEmMemoria\u0026lt;String\u0026gt;()) repo.salvar(\u0026#34;Kotlin Brasil\u0026#34;) repo.salvar(\u0026#34;Tutorial de Interfaces\u0026#34;) println(\u0026#34;Total de itens: ${repo.listar().size}\u0026#34;) // 2 println(\u0026#34;Itens: ${repo.listar()}\u0026#34;) repo.remover(\u0026#34;id-1\u0026#34;) } Delegation é a alternativa do Kotlin ao padrão Decorator. Em vez de herdar de uma classe concreta, você compõe comportamento delegando a implementação e sobrescrevendo apenas o que precisa. Essa abordagem favorece composição sobre herança, que é uma das boas práticas mais recomendadas em design orientado a objetos.\nInterfaces como Contratos de API Interfaces são fundamentais para criar código testável e desacoplado. Ao programar contra interfaces, você podé fácilmente trocar implementações, criar mocks para testes e seguir princípios SOLID.\ninterface ServicoDeEmail { fun enviar(destinatario: String, assunto: String, corpo: String): Boolean } class SmtpEmailService : ServicoDeEmail { override fun enviar(destinatario: String, assunto: String, corpo: String): Boolean { println(\u0026#34;Enviando via SMTP para $destinatario: $assunto\u0026#34;) return true } } class MockEmailService : ServicoDeEmail { val emailsEnviados = mutableListOf\u0026lt;String\u0026gt;() override fun enviar(destinatario: String, assunto: String, corpo: String): Boolean { emailsEnviados.add(\u0026#34;$destinatario: $assunto\u0026#34;) return true } } class NotificacaoService(private val emailService: ServicoDeEmail) { fun notificar(email: String, mensagem: String) { emailService.enviar(email, \u0026#34;Notificação\u0026#34;, mensagem) } } fun main() { // Em produção val prodService = NotificacaoService(SmtpEmailService()) prodService.notificar(\u0026#34;user@email.com\u0026#34;, \u0026#34;Bem-vindo!\u0026#34;) // Em testes val mockEmail = MockEmailService() val testService = NotificacaoService(mockEmail) testService.notificar(\u0026#34;teste@email.com\u0026#34;, \u0026#34;Teste\u0026#34;) println(\u0026#34;Emails enviados: ${mockEmail.emailsEnviados}\u0026#34;) } Erros Comuns Tentar armazenar estado em interfaces. Interfaces não podem ter backing fields. Uma propriedade em interface pode ter um getter, mas não pode inicializar um valor diretamente como val x = 5.\nEsquecer de resolver conflitos. Quando duas interfaces definem o mesmo método com implementação padrão, a classe deve sobrescrever e decidir qual usar. Ignorar isso causa erro de compilação.\nUsar interface quando classe abstrata seria melhor. Se você precisa de estado compartilhado (properties com backing field) e construtores, uma classe abstrata é mais apropriada. Interfaces são ideais para contratos sem estado.\nDelegation com estado mutável. Ao usar by para delegação, lembre-se de que o objeto delegado é compartilhado. Mudanças de estado no delegado afetam todos que possuem referência a ele.\nConclusão e Próximos Passos Neste tutorial, você aprendeu a usar interfaces em Kotlin de forma completa: declaração e implementação, default methods, properties, herança múltipla, delegation e uso como contratos de API. Interfaces são fundamentais para escrever código desacoplado, testável e bem arquitetado.\nO próximo passo é estudar null safety em Kotlin, uma das funcionalidades mais importantes da linguagem que elimina erros de NullPointerException. Recomendamos também explorar generics para criar interfaces parametrizadas e extension functions para estender interfaces existentes. Com domínio de interfaces e herança, você possui uma base sólida de OOP para construir projetos Kotlin robustos e escaláveis.\n","permalink":"https://kotlin.dev.br/tutoriais/interfaces-kotlin/","summary":"\u003cp\u003eNeste tutorial, vamos explorar interfaces em Kotlin de forma completa e prática. \u003ca href=\"/glossario/interface/\"\u003eInterfaces\u003c/a\u003e definem um contrato que classes devem seguir, sem impor uma hierarquia rígida de herança. Diferente de Java até a versão 7, as interfaces em Kotlin podem conter implementações padrão de métodos e até propriedades com acessores. Você aprenderá a declarar e implementar interfaces, usar default methods, definir properties em interfaces, trabalhar com herança múltipla de interfaces e aplicar interface delegation.\u003c/p\u003e","title":"Interfaces em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Neste tutorial, vamos aprender tudo sobre herança em Kotlin. Herança é um dos pilares da programação orientada a objetos e permite que uma classe filha reutilize e estenda o comportamento de uma classe pai. Diferente de Java, onde todas as classes são abertas para herança por padrão, o Kotlin adota uma postura mais segura: classes são finais por padrão. Vamos explorar como usar open, override, super, classes abstratas, introdução a sealed classes é a classe Any.\nA Classe Any: A Raiz de Tudo Em Kotlin, todas as classes herdam implicitamente de Any. Essa classe é a raiz da hierarquia de tipos e fornece três métodos fundamentais: equals(), hashCode() e toString(). Qualquer classe que você crie já possui esses métodos herdados.\nclass MinhaClasse fun main() { val obj = MinhaClasse() // Métodos herdados de Any println(obj.toString()) // MinhaClasse@\u0026lt;hash\u0026gt; println(obj.hashCode()) // Código hash numérico println(obj.equals(obj)) // true // \u0026#39;is\u0026#39; verifica o tipo (como instanceof em Java) println(obj is Any) // true — tudo é Any } Diferente de Java, onde Object é a raiz, Any em Kotlin não possui os métodos wait(), notify() e clone(). Essa simplificação reflete a filosofia do Kotlin de manter a API limpa e moderna.\nOpen Classes e Herança Básica Por padrão, todas as classes em Kotlin são final — não podem ser herdadas. Para permitir que uma classe sirva de base para outras, você precisa marcá-la explicitamente com o modificador open. Da mesma forma, métodos e propriedades que podem ser sobrescritos também devem ser open.\nopen class Animal(val nome: String, val peso: Double) { open fun emitirSom(): String { return \u0026#34;$nome faz um som.\u0026#34; } open fun descricao(): String { return \u0026#34;Animal: $nome, Peso: ${peso}kg\u0026#34; } // Função SEM open — nao pode ser sobrescrita fun identificador(): String = \u0026#34;Animal-${nome.uppercase()}\u0026#34; } class Cachorro(nome: String, peso: Double, val raca: String) : Animal(nome, peso) { override fun emitirSom(): String { return \u0026#34;$nome late: Au au!\u0026#34; } override fun descricao(): String { return \u0026#34;Cachorro: $nome ($raca), Peso: ${peso}kg\u0026#34; } } class Gato(nome: String, peso: Double) : Animal(nome, peso) { override fun emitirSom(): String { return \u0026#34;$nome mia: Miau!\u0026#34; } } fun main() { val dog = Cachorro(\u0026#34;Rex\u0026#34;, 25.0, \u0026#34;Pastor Alemão\u0026#34;) val cat = Gato(\u0026#34;Mimi\u0026#34;, 4.5) println(dog.emitirSom()) // Rex late: Au au! println(dog.descricao()) // Cachorro: Rex (Pastor Alemão), Peso: 25.0kg println(dog.identificador()) // Animal-REX println(cat.emitirSom()) // Mimi mia: Miau! println(cat.descricao()) // Animal: Mimi, Peso: 4.5kg } A decisão de tornar classes finais por padrão é uma escolha deliberada de design. O livro \u0026ldquo;Effective Java\u0026rdquo; de Joshua Bloch recomenda \u0026ldquo;projetar para herança ou proibi-la\u0026rdquo;, e o Kotlin segue exatamente esse princípio. Você precisa pensar conscientemente antes de abrir uma classe para extensão.\nUsando super para Chamar a Classe Pai A palavra-chave super permite acessar implementações da classe pai dentro de uma classe filha. Isso é útil quando você quer estender o comportamento existente em vez de substituí-lo completamente.\nopen class Veiculo(val marca: String, val modelo: String, val ano: Int) { open fun info(): String { return \u0026#34;$marca $modelo ($ano)\u0026#34; } open fun ligar(): String { return \u0026#34;Veículo ligado. Verificações basicas realizadas.\u0026#34; } } class CarroEletrico( marca: String, modelo: String, ano: Int, val autonomiaKm: Int ) : Veiculo(marca, modelo, ano) { override fun info(): String { // Usa a implementacao da classe pai e adiciona informacao return \u0026#34;${super.info()} — Elétrico, Autonomia: ${autonomiaKm}km\u0026#34; } override fun ligar(): String { val basico = super.ligar() return \u0026#34;$basico\\nBateria verificada. Motor elétrico pronto.\u0026#34; } } fun main() { val tesla = CarroEletrico(\u0026#34;Tesla\u0026#34;, \u0026#34;Model 3\u0026#34;, 2024, 450) println(tesla.info()) // Tesla Model 3 (2024) — Elétrico, Autonomia: 450km println(tesla.ligar()) // Veículo ligado. Verificações basicas realizadas. // Bateria verificada. Motor elétrico pronto. } O padrão de chamar super e depois adicionar comportamento específico é muito comum e é considerado boa prática, pois garante que a lógica da classe pai sempre será executada.\nClasses Abstratas Classes abstratas não podem ser instanciadas diretamente e podem conter tanto membros abstratos (sem implementação) quanto membros concretos (com implementação). Diferente de classes open, classes abstratas já são abertas para herança por natureza.\nabstract class FormaPagamento(val titular: String) { // Método abstrato: subclasses DEVEM implementar abstract fun processar(valor: Double): Boolean abstract fun nomeMetodo(): String // Método concreto: subclasses herdam automaticamente fun recibo(valor: Double): String { return \u0026#34;Recibo: R$${\u0026#34;%.2f\u0026#34;.format(valor)} via ${nomeMetodo()} - Titular: $titular\u0026#34; } } class CartaoCredito(titular: String, val bandeira: String) : FormaPagamento(titular) { override fun processar(valor: Double): Boolean { println(\u0026#34;Processando R$${\u0026#34;%.2f\u0026#34;.format(valor)} no cartão $bandeira de $titular...\u0026#34;) return valor \u0026lt;= 5000.0 // Limite simplificado } override fun nomeMetodo() = \u0026#34;Cartão $bandeira\u0026#34; } class Pix(titular: String, val chave: String) : FormaPagamento(titular) { override fun processar(valor: Double): Boolean { println(\u0026#34;Processando Pix de R$${\u0026#34;%.2f\u0026#34;.format(valor)} para chave $chave...\u0026#34;) return true // Pix sempre processa (simplificação) } override fun nomeMetodo() = \u0026#34;Pix ($chave)\u0026#34; } fun main() { val pagamentos: List\u0026lt;FormaPagamento\u0026gt; = listOf( CartaoCredito(\u0026#34;Maria Silva\u0026#34;, \u0026#34;Visa\u0026#34;), Pix(\u0026#34;João Santos\u0026#34;, \u0026#34;joao@email.com\u0026#34;) ) for (pagamento in pagamentos) { val sucesso = pagamento.processar(150.0) if (sucesso) { println(pagamento.recibo(150.0)) } println() } } Classes abstratas são ideais quando você quer fornecer uma implementação parcial que subclasses devem completar. Elas definem um contrato enquanto oferecem código reutilizável — um equilíbrio entre interfaces (totalmente abstratas) e classes concretas.\nIntrodução a Sealed Classes Sealed classes restringem a hierarquia de herança a um conjunto finito e conhecido de subclasses. Todas as subclasses diretas devem ser declaradas no mesmo arquivo. Isso permite que o compilador saiba exatamente quais tipos são possíveis, habilitando verificações exaustivas com when.\nsealed class Resultado { data class Sucesso(val dados: String) : Resultado() data class Erro(val mensagem: String, val codigo: Int) : Resultado() data object Carregando : Resultado() } fun tratarResultado(resultado: Resultado): String { // O \u0026#39;when\u0026#39; é exaustivo: o compilador garante que todos os casos são cobertos return when (resultado) { is Resultado.Sucesso -\u0026gt; \u0026#34;Dados: ${resultado.dados}\u0026#34; is Resultado.Erro -\u0026gt; \u0026#34;Erro ${resultado.codigo}: ${resultado.mensagem}\u0026#34; is Resultado.Carregando -\u0026gt; \u0026#34;Aguarde, carregando...\u0026#34; // Não precisa de \u0026#39;else\u0026#39; — todos os tipos estão cobertos } } fun main() { val resultados = listOf( Resultado.Carregando, Resultado.Sucesso(\u0026#34;Lista de usuários carregada\u0026#34;), Resultado.Erro(\u0026#34;Não encontrado\u0026#34;, 404) ) for (r in resultados) { println(tratarResultado(r)) } } Sealed classes são extremamente úteis para modelar estados de uma aplicação, respostas de API e qualquer cenário onde o conjunto de possibilidades é fechado e conhecido. Elas são amplamente usadas no desenvolvimento Android moderno com Jetpack Compose.\nSobrescrevendo Properties Além de métodos, você também pode sobrescrever propriedades da classe pai. A propriedade na classe pai deve ser open, e a subclasse usa override.\nopen class Conta(open val limite: Double = 1000.0) { open val tipo: String = \u0026#34;Básica\u0026#34; fun info() = \u0026#34;Conta $tipo — Limite: R$${\u0026#34;%.2f\u0026#34;.format(limite)}\u0026#34; } class ContaPremium : Conta() { override val limite: Double = 10000.0 override val tipo: String = \u0026#34;Premium\u0026#34; } class ContaEmpresarial(override val limite: Double) : Conta() { override val tipo: String = \u0026#34;Empresarial\u0026#34; } fun main() { val basica = Conta() val premium = ContaPremium() val empresarial = ContaEmpresarial(50000.0) println(basica.info()) // Conta Básica — Limite: R$1000.00 println(premium.info()) // Conta Premium — Limite: R$10000.00 println(empresarial.info()) // Conta Empresarial — Limite: R$50000.00 } Uma propriedade val na classe pai pode ser sobrescrita por uma var na subclasse (ampliando o acesso), mas o contrário não é permitido. Isso segue o princípio de que uma subclasse pode ser mais permissiva, mas não mais restritiva.\nErros Comuns Esquecer de marcar a classe com open. Tentar herdar de uma classe sem o modificador open resulta em erro de compilação. Essa é a causa mais frequente de confusão para desenvolvedores vindos de Java.\nEsquecer override no método sobrescrito. Diferente de Java onde @Override é opcional, em Kotlin o override é obrigatório. Omiti-lo causa erro de compilação.\nChamar métodos abstratos no construtor. Chamar um método open ou abstrato dentro do init block ou construtor da classe pai é perigoso, pois a subclasse ainda não foi completamente inicializada nesse ponto.\nConfundir sealed class com enum. Sealed classes permitem que cada subclasse tenha propriedades e estados diferentes. Enums são constantes únicas. Use sealed quando os tipos filhos precisam de dados distintos.\nConclusão e Próximos Passos Neste tutorial, você aprendeu os fundamentos de herança em Kotlin: desde a classe Any, passando por open classes, override, super, classes abstratas, sealed classes e sobrescrita de propriedades. Esses conceitos permitem criar hierarquias de tipos seguras e expressivas.\nO próximo passo natural é estudar interfaces em Kotlin, que complementam a herança permitindo múltiplas implementações. Também recomendamos explorar delegation, uma alternativa poderosa à herança que favorece composição. Com domínio de herança e interfaces, você terá uma compreensão completa de OOP em Kotlin e estará pronto para projetar arquiteturas robustas em seus projetos.\n","permalink":"https://kotlin.dev.br/tutoriais/heranca-kotlin/","summary":"\u003cp\u003eNeste tutorial, vamos aprender tudo sobre herança em Kotlin. Herança é um dos pilares da programação orientada a objetos e permite que uma \u003ca href=\"/glossario/class/\"\u003eclasse\u003c/a\u003e filha reutilize e estenda o comportamento de uma classe pai. Diferente de Java, onde todas as classes são abertas para herança por padrão, o Kotlin adota uma postura mais segura: classes são finais por padrão. Vamos explorar como usar \u003ccode\u003eopen\u003c/code\u003e, \u003ccode\u003eoverride\u003c/code\u003e, \u003ccode\u003esuper\u003c/code\u003e, classes \u003ca href=\"/glossario/abstract/\"\u003eabstratas\u003c/a\u003e, introdução a \u003ca href=\"/glossario/sealed-class/\"\u003esealed classes\u003c/a\u003e é a classe \u003ccode\u003eAny\u003c/code\u003e.\u003c/p\u003e","title":"Herança em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Neste tutorial, vamos explorar em profundidade o sistema de variáveis e tipos de dados do Kotlin. Você vai aprender a diferença entre val e var, conhecer todos os tipos primitivos disponíveis e dominar a inferência de tipos, que é uma das funcionalidades mais poderosas da linguagem.\nDeclaração de Variáveis: val vs var Em Kotlin, existem duas formas de declarar variáveis: usando val para valores imutáveis e var para valores mutáveis. Essa distinção é fundamental e afeta diretamente a qualidade e segurança do seu código.\nA palavra-chave val (de \u0026ldquo;value\u0026rdquo;) cria uma variável que não pode ter seu valor reatribuído após a inicialização. Pense nela como uma constante local. Já var (de \u0026ldquo;variable\u0026rdquo;) permite que o valor seja alterado quantas vezes forem necessárias.\nfun main() { // val - imutável: nao pode ser reatribuída val nome = \u0026#34;Maria\u0026#34; val idade = 28 val pi = 3.14159 // var - mutável: pode ser reatribuída var contador = 0 var saldo = 1000.50 var ativo = true // Isso funciona: contador = 1 saldo = 950.75 ativo = false // Isso NÃO compila (val nao pode ser reatribuído): // nome = \u0026#34;João\u0026#34; // Erro: Val cannot be reassigned println(\u0026#34;Nome: $nome, Idade: $idade\u0026#34;) println(\u0026#34;Contador: $contador, Saldo: R$$saldo, Ativo: $ativo\u0026#34;) } A regra de ouro em Kotlin é: sempre comece com val. Só mude para var quando você realmente precisar modificar o valor. Isso torna o código mais previsível, facilita o raciocínio sobre o programa e reduz bugs relacionados a estado mutável. Em programação funcional e concorrente, a imutabilidade é especialmente valiosa porque elimina uma classe inteira de problemas de sincronização.\nÉ importante entender que val torna a referência imutável, não necessariamente o objeto em si. Por exemplo, uma lista mutável atribuída a um val ainda pode ter seus elementos alterados — o que não pode mudar é a referência para outra lista.\nTipos Primitivos em Kotlin Kotlin possui um conjunto completo de tipos de dados que cobrem as necessidades mais comuns de programação. Diferentemente de Java, em Kotlin todos os tipos são objetos, mas o compilador otimiza automaticamente os tipos numéricos para primitivos da JVM quando possível.\nTipos Numéricos Inteiros Kotlin oferece quatro tipos inteiros com diferentes tamanhos, cada um adequado para diferentes cenários:\nfun main() { // Byte: 8 bits (-128 a 127) val pequeno: Byte = 127 // Short: 16 bits (-32768 a 32767) val medio: Short = 32000 // Int: 32 bits (-2^31 a 2^31 - 1) — padrao para inteiros val normal: Int = 2_000_000_000 val outroInt = 42 // inferido como Int // Long: 64 bits (-2^63 a 2^63 - 1) val grande: Long = 9_000_000_000_000L val outroLong = 100L // sufixo L força Long println(\u0026#34;Byte: $pequeno\u0026#34;) println(\u0026#34;Short: $medio\u0026#34;) println(\u0026#34;Int: $normal (outro: $outroInt)\u0026#34;) println(\u0026#34;Long: $grande (outro: $outroLong)\u0026#34;) // Underscores em numeros para legibilidade val umMilhao = 1_000_000 val cartaoCredito = 1234_5678_9012_3456L val hexadecimal = 0xFF_EC_DE_5E val binario = 0b1010_0101 println(\u0026#34;Um milhão: $umMilhao\u0026#34;) println(\u0026#34;Hex: $hexadecimal, Binário: $binario\u0026#34;) } Observe o uso de underscores nos números literais. Esse recurso melhora significativamente a legibilidade de números grandes sem afetar o valor. O compilador simplesmente ignora os underscores.\nTipos de Ponto Flutuante Para números decimais, Kotlin disponibiliza dois tipos: Float (32 bits, precisão simples) e Double (64 bits, precisão dupla). O tipo padrão para literais decimais é Double.\nfun main() { // Double: 64 bits — padrao para decimais val preco = 29.99 // inferido como Double val temperatura: Double = -3.5 // Float: 32 bits — precisa do sufixo \u0026#39;f\u0026#39; ou \u0026#39;F\u0026#39; val taxa: Float = 0.15f val percentual = 85.5f // Operações com decimais val subtotal = 100.0 val desconto = subtotal * 0.10 val total = subtotal - desconto println(\u0026#34;Subtotal: R$$subtotal\u0026#34;) println(\u0026#34;Desconto: R$$desconto\u0026#34;) println(\u0026#34;Total: R$$total\u0026#34;) // Cuidado com precisão de ponto flutuante println(\u0026#34;0.1 + 0.2 = ${0.1 + 0.2}\u0026#34;) // 0.30000000000000004 } Para cálculos financeiros onde a precisão é crítica, considere usar BigDecimal em vez de Double ou Float. Os tipos de ponto flutuante seguem o padrão IEEE 754 e podem apresentar pequenas imprecisões em certas operações.\nTipos Boolean, Char e String Além dos numéricos, Kotlin possui tipos essenciais para trabalhar com valores lógicos, caracteres e texto.\nO tipo Boolean representa valores true ou false e é amplamente utilizado em estruturas condicionais. O tipo Char representa um único caractere Unicode e é delimitado por aspas simples. Já String representa uma sequência de caracteres e é delimitada por aspas duplas.\nfun main() { // Boolean val ativo: Boolean = true val maiorDeIdade = false // inferido como Boolean val resultado = 10 \u0026gt; 5 // true // Char val letra: Char = \u0026#39;A\u0026#39; val digito = \u0026#39;7\u0026#39; val emoji = \u0026#39;\\u2764\u0026#39; // caractere Unicode (coração) // String val saudacao = \u0026#34;Olá, Kotlin!\u0026#34; val multilinhas = \u0026#34;\u0026#34;\u0026#34; |Primeira linha |Segunda linha |Terceira linha \u0026#34;\u0026#34;\u0026#34;.trimMargin() // String templates val nome = \u0026#34;Ana\u0026#34; val idade = 25 val apresentacao = \u0026#34;Meu nome é $nome e tenho $idade anos.\u0026#34; val calculo = \u0026#34;Daqui a 5 anos terei ${idade + 5} anos.\u0026#34; println(\u0026#34;Boolean: $ativo, $maiorDeIdade, $resultado\u0026#34;) println(\u0026#34;Char: $letra, $digito, $emoji\u0026#34;) println(saudacao) println(multilinhas) println(apresentacao) println(calculo) } As string templates são um recurso extremamente útil do Kotlin. Elas permitem incorporar variáveis diretamente no texto com $variavel e expressões mais complexas com ${expressao}. Isso elimina a necessidade de concatenação manual com o operador +, tornando o código mais limpo e legível.\nInferência de Tipos e Conversões O sistema de inferência de tipos do Kotlin é sofisticado e inteligente. O compilador consegue deduzir automaticamente o tipo de uma variável com base no valor atribuído a ela, eliminando a necessidade de declarações explícitas na maioria dos casos.\nQuando você escreve val x = 42, o compilador sabe que x é do tipo Int. Quando escreve val nome = \u0026quot;Kotlin\u0026quot;, ele sabe que é String. Essa inferência funciona em praticamente todos os contextos, incluindo retornos de funções e expressões complexas.\nNo entanto, diferente de algumas linguagens, Kotlin não faz conversões implícitas entre tipos numéricos. Você precisa usar funções de conversão explícitas como toInt(), toLong(), toDouble() e assim por diante.\nfun main() { // Inferência de tipos val numero = 42 // Int val decimal = 3.14 // Double val texto = \u0026#34;Kotlin\u0026#34; // String val flag = true // Boolean // Conversoes explícitas (nao há conversao implícita!) val inteiro: Int = 100 val longo: Long = inteiro.toLong() // Int -\u0026gt; Long val decimal2: Double = inteiro.toDouble() // Int -\u0026gt; Double val flutuante: Float = decimal2.toFloat() // Double -\u0026gt; Float val byte: Byte = inteiro.toByte() // Int -\u0026gt; Byte // Conversao String -\u0026gt; Número val textoNumero = \u0026#34;123\u0026#34; val convertido = textoNumero.toInt() val seguro = \u0026#34;abc\u0026#34;.toIntOrNull() // retorna null em vez de excecao println(\u0026#34;Convertido: $convertido\u0026#34;) println(\u0026#34;Seguro: $seguro\u0026#34;) // null // Tipo explícito quando necessario val valor: Long = 42 // sem o tipo, seria inferido como Int // Checagem de tipo com \u0026#39;is\u0026#39; val algo: Any = \u0026#34;Sou uma String\u0026#34; if (algo is String) { // Smart cast: \u0026#39;algo\u0026#39; já é tratado como String aqui println(\u0026#34;Tamanho: ${algo.length}\u0026#34;) } } O recurso de smart cast é uma funcionalidade elegante do Kotlin. Quando você verifica o tipo de uma variável com is, o compilador automaticamente faz o cast dentro do bloco condicional, eliminando a necessidade de casts manuais como em Java. Isso funciona com verificações de null safety também.\nConstantes de Compilação com const val Além de val, Kotlin oferece const val para constantes que são resolvidas em tempo de compilação. Essas constantes devem ser do tipo String ou de um tipo primitivo, e só podem ser declaradas no nível superior do arquivo ou dentro de um companion object.\nA diferença entre val e const val é sutil mas importante: val é resolvido em tempo de execução (o valor pode ser calculado), enquanto const val precisa ser um valor literal conhecido em tempo de compilação.\nDicas e Erros Comuns Ao trabalhar com variáveis e tipos em Kotlin, fique atento aos seguintes pontos que costumam causar confusão em iniciantes:\nUsar var quando val bastaria: essa é a armadilha mais comum. Sempre comece com val e só mude para var se realmente precisar reatribuir o valor. IDEs como IntelliJ IDEA avisam quando um var poderia ser val.\nEsperar conversão implícita entre tipos numéricos: diferente de Java, val x: Long = 42 não converte automaticamente o Int 42 para Long em todos os contextos. Use 42L ou .toLong() quando necessário.\nConfundir imutabilidade da referência com imutabilidade do objeto: val lista = mutableListOf(1, 2, 3) impede reatribuir lista, mas permite modificar o conteúdo com lista.add(4). Para imutabilidade completa, use listOf().\nNão usar toIntOrNull() para conversões seguras: se você tentar \u0026quot;abc\u0026quot;.toInt(), vai receber uma exceção. Sempre use toIntOrNull() quando a conversão pode falhar, e trate o resultado null com o operador Elvis ?:.\nDeclarar tipos desnecessariamente: aproveite a inferência de tipos. Escreva val nome = \u0026quot;Kotlin\u0026quot; em vez de val nome: String = \u0026quot;Kotlin\u0026quot;. A declaração explícita só é necessária quando o tipo não pode ser inferido ou quando você quer um tipo diferente do inferido.\nConclusão e Próximos Passos Dominar variáveis e tipos de dados é a base para qualquer programação eficaz em Kotlin. Você aprendeu a diferença crucial entre val e var, conheceu todos os tipos primitivos disponíveis, entendeu a inferência de tipos e as conversões explícitas, e viu como smart casts tornam o código mais seguro e elegante.\nPara continuar sua jornada de aprendizado, recomendo os seguintes tutoriais:\nEstruturas Condicionais — aprenda a usar if, when e controlar o fluxo do programa Funções em Kotlin — descubra como criar funções com parâmetros tipados Null Safety — domine o sistema de segurança contra nulos do Kotlin Pratique criando pequenos programas que utilizem diferentes tipos de dados e conversões. A familiaridade com o sistema de tipos do Kotlin vai facilitar enormemente seu aprendizado nos tópicos mais avançados.\n","permalink":"https://kotlin.dev.br/tutoriais/variaveis-e-tipos/","summary":"\u003cp\u003eNeste tutorial, vamos explorar em profundidade o sistema de variáveis e tipos de dados do Kotlin. Você vai aprender a diferença entre \u003ccode\u003eval\u003c/code\u003e e \u003ccode\u003evar\u003c/code\u003e, conhecer todos os tipos primitivos disponíveis e dominar a inferência de tipos, que é uma das funcionalidades mais poderosas da linguagem.\u003c/p\u003e\n\u003ch2 id=\"declaração-de-variáveis-val-vs-var\"\u003eDeclaração de Variáveis: val vs var\u003c/h2\u003e\n\u003cp\u003eEm Kotlin, existem duas formas de declarar \u003ca href=\"/glossario/variaveis/\"\u003evariáveis\u003c/a\u003e: usando \u003ccode\u003eval\u003c/code\u003e para valores imutáveis e \u003ccode\u003evar\u003c/code\u003e para valores mutáveis. Essa distinção é fundamental e afeta diretamente a qualidade e segurança do seu código.\u003c/p\u003e","title":"Variáveis e Tipos de Dados em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Neste tutorial, vamos explorar em profundidade o sistema de classes e objetos do Kotlin. Programação orientada a objetos (OOP) é um dos paradigmas mais utilizados no desenvolvimento de software, é o Kotlin oferece uma implementação moderna e concisa desses conceitos. Você aprenderá a declarar classes, usar construtores primários e secundários, definir properties com getters e setters personalizados, trabalhar com init blocks, companion objects e modificadores de visibilidade.\nDeclaração de Classes Em Kotlin, classes são declaradas com a palavra-chave class. A forma mais simples de criar uma classe não exige nenhum corpo — apenas o nome é suficiente. Quando a classe possui propriedades e métodos, o corpo é delimitado por chaves.\n// Classe vazia (valida em Kotlin) class Vazio // Classe com propriedades e metodos class Pessoa { var nome: String = \u0026#34;\u0026#34; var idade: Int = 0 fun apresentar(): String { return \u0026#34;Olá, meu nome é $nome e tenho $idade anos.\u0026#34; } } fun main() { val pessoa = Pessoa() pessoa.nome = \u0026#34;Mariana\u0026#34; pessoa.idade = 28 println(pessoa.apresentar()) // Olá, meu nome é Mariana e tenho 28 anos. } Observe que em Kotlin não usamos a palavra-chave new para criar instâncias. Basta chamar o nome da classe como uma função. Isso torna a criação de objetos mais limpa e natural.\nConstrutor Primário O construtor primário faz parte da declaração da classe e é colocado logo após o nome. Parâmetros precedidos por val ou var automaticamente se tornam propriedades da classe, eliminando a necessidade de declaração manual e atribuição no corpo.\nclass Usuario( val nome: String, val email: String, var ativo: Boolean = true ) { fun resumo() = \u0026#34;Usuário: $nome ($email) - Ativo: $ativo\u0026#34; } fun main() { val user1 = Usuario(\u0026#34;Carlos\u0026#34;, \u0026#34;carlos@email.com\u0026#34;) val user2 = Usuario(\u0026#34;Ana\u0026#34;, \u0026#34;ana@email.com\u0026#34;, false) println(user1.resumo()) // Usuário: Carlos (carlos@email.com) - Ativo: true println(user2.resumo()) // Usuário: Ana (ana@email.com) - Ativo: false user1.ativo = false // \u0026#39;var\u0026#39; permite reatribuição // user1.nome = \u0026#34;Outro\u0026#34; // ERRO: \u0026#39;val\u0026#39; é imutável } Essa é uma das grandes vantagens do Kotlin sobre o Java: o construtor primário com declaração de propriedades reduz drasticamente o boilerplate. O que em Java exigiria campos privados, construtor e getters/setters, em Kotlin se resolve em poucas linhas.\nConstrutor Secundário Construtores secundários são declarados dentro do corpo da classe usando a palavra-chave constructor. Eles devem delegar para o construtor primário, direta ou indiretamente, usando this().\nclass Produto(val nome: String, val preco: Double) { var categoria: String = \u0026#34;Geral\u0026#34; var estoque: Int = 0 // Construtor secundário que delega para o primário constructor(nome: String, preco: Double, categoria: String) : this(nome, preco) { this.categoria = categoria } constructor(nome: String, preco: Double, categoria: String, estoque: Int) : this(nome, preco, categoria) { this.estoque = estoque } fun detalhes() = \u0026#34;$nome | R$${\u0026#34;%.2f\u0026#34;.format(preco)} | $categoria | Estoque: $estoque\u0026#34; } fun main() { val p1 = Produto(\u0026#34;Teclado\u0026#34;, 199.90) val p2 = Produto(\u0026#34;Mouse\u0026#34;, 89.90, \u0026#34;Periféricos\u0026#34;) val p3 = Produto(\u0026#34;Monitor\u0026#34;, 1299.00, \u0026#34;Monitores\u0026#34;, 15) println(p1.detalhes()) // Teclado | R$199.90 | Geral | Estoque: 0 println(p2.detalhes()) // Mouse | R$89.90 | Periféricos | Estoque: 0 println(p3.detalhes()) // Monitor | R$1299.00 | Monitores | Estoque: 15 } Na prática, construtores secundários são menos comuns em Kotlin do que em Java, porque default parameters no construtor primário resolvem a maioria dos casos de sobrecarga.\nProperties: Getters e Setters Personalizados Em Kotlin, toda propriedade tem um getter implícito (e um setter, se for var). Você pode personalizar esses acessores para adicionar lógica de válidação ou transformação.\nclass ContaBancaria(val titular: String, saldoInicial: Double) { var saldo: Double = saldoInicial private set // setter é privado: só a própria classe altera val estaPositiva: Boolean get() = saldo \u0026gt; 0 // getter personalizado (calculado a cada acesso) var email: String = \u0026#34;\u0026#34; set(value) { if (value.contains(\u0026#34;@\u0026#34;)) { field = value.lowercase() } else { println(\u0026#34;Email invalido: $value\u0026#34;) } } fun depositar(valor: Double) { if (valor \u0026gt; 0) saldo += valor } fun sacar(valor: Double): Boolean { return if (valor in 0.01..saldo) { saldo -= valor true } else { false } } } fun main() { val conta = ContaBancaria(\u0026#34;João Silva\u0026#34;, 1000.0) conta.depositar(500.0) println(\u0026#34;Saldo: R$${conta.saldo}\u0026#34;) // Saldo: R$1500.0 println(\u0026#34;Positiva: ${conta.estaPositiva}\u0026#34;) // Positiva: true conta.email = \u0026#34;JOAO@Email.COM\u0026#34; println(\u0026#34;Email: ${conta.email}\u0026#34;) // Email: joao@email.com conta.email = \u0026#34;invalido\u0026#34; // Email invalido: invalido } A palavra-chave field dentro do setter é o backing field — a referência real ao valor armazenado. Sem ela, atribuir diretamente à propriedade dentro do seu próprio setter causaria uma recursão infinita.\nInit Blocks O bloco init é executado imediatamente após o construtor primário, na ordem em que aparece no corpo da classe. Você pode ter múltiplos blocos init, e eles são úteis para válidações e lógica de inicialização.\nclass Pedido(val cliente: String, val itens: List\u0026lt;String\u0026gt;) { val totalItens: Int val status: String init { require(cliente.isNotBlank()) { \u0026#34;Nome do cliente nao pode ser vazio\u0026#34; } require(itens.isNotEmpty()) { \u0026#34;Pedido deve ter pelo menos um item\u0026#34; } totalItens = itens.size } init { status = if (totalItens \u0026gt; 5) \u0026#34;Grande\u0026#34; else \u0026#34;Normal\u0026#34; println(\u0026#34;Pedido criado para $cliente com $totalItens itens [$status]\u0026#34;) } fun resumo() = \u0026#34;Pedido de $cliente: ${itens.joinToString(\u0026#34;, \u0026#34;)} ($status)\u0026#34; } fun main() { val pedido = Pedido(\u0026#34;Maria\u0026#34;, listOf(\u0026#34;Arroz\u0026#34;, \u0026#34;Feijão\u0026#34;, \u0026#34;Café\u0026#34;)) println(pedido.resumo()) // Pedido de Maria: Arroz, Feijão, Café (Normal) // Isso lançaria IllegalArgumentException: // val pedidoInvalido = Pedido(\u0026#34;\u0026#34;, listOf(\u0026#34;Item\u0026#34;)) } Blocos init são executados como parte do construtor primário, intercalados com as inicializações de propriedades na ordem em que aparecem no código-fonte.\nCompanion Objects Em Kotlin não existem membros estáticos como em Java. A alternativa é o companion object, um objeto singleton associado à classe que pode conter propriedades e funções acessíveis pelo nome da classe.\nclass Configuração private constructor(val ambiente: String, val debug: Boolean) { companion object { private const val VERSAO = \u0026#34;1.0.0\u0026#34; fun desenvolvimento() = Configuração(\u0026#34;dev\u0026#34;, true) fun producao() = Configuração(\u0026#34;prod\u0026#34;, false) fun versao() = VERSAO } fun info() = \u0026#34;Ambiente: $ambiente | Debug: $debug | Versão: ${versao()}\u0026#34; } fun main() { val configDev = Configuração.desenvolvimento() val configProd = Configuração.producao() println(configDev.info()) // Ambiente: dev | Debug: true | Versão: 1.0.0 println(configProd.info()) // Ambiente: prod | Debug: false | Versão: 1.0.0 println(Configuração.versao()) // 1.0.0 } Companion objects são frequentemente usados para implementar o padrão Factory Method, como no exemplo acima, onde o construtor é privado e as instâncias são criadas por meio de funções descritivas.\nModificadores de Visibilidade Kotlin oferece quatro modificadores de visibilidade que controlam o acesso a classes, funções e propriedades:\nclass ExemploVisibilidade { public val publico = \u0026#34;Acessível de qualquer lugar\u0026#34; // padrao private val privado = \u0026#34;Só dentro desta classe\u0026#34; protected val protegido = \u0026#34;Nesta classe e subclasses\u0026#34; internal val interno = \u0026#34;Dentro do mesmo módulo\u0026#34; private fun metodoPrivado() = \u0026#34;Lógica interna\u0026#34; fun metodoPublico(): String { // Pode acessar todos os membros return \u0026#34;$publico | ${metodoPrivado()}\u0026#34; } } // Top-level: \u0026#39;protected\u0026#39; nao é permitido private fun funcaoPrivadaDoArquivo() = \u0026#34;Visível apenas neste arquivo\u0026#34; internal fun funcaoInterna() = \u0026#34;Visível no módulo\u0026#34; Em Kotlin, o padrão é public, diferente de Java onde o padrão é package-private. O modificador internal é único do Kotlin e restringe o acesso ao módulo de compilação, sendo muito útil para bibliotecas que querem esconder detalhes de implementação.\nErros Comuns Esquecer val ou var no construtor primário. Parâmetros do construtor sem val/var não se tornam propriedades da classe. Eles só existem durante a execução do construtor e dos blocos init.\n// ERRADO: \u0026#39;nome\u0026#39; nao é propriedade, nao pode ser acessado depois // class Errada(nome: String) { fun getNome() = nome } // Erro // CORRETO class Correta(val nome: String) Recursão infinita no setter. Usar o nome da propriedade dentro do seu próprio setter em vez de field causa um loop infinito que resulta em StackOverflowError.\nConfundir companion object com instância. Membros do companion object pertencem à classe, não a instâncias individuais. Tentar acessar propriedades de instância dentro do companion object causa erro de compilação.\nIgnorar init order. Propriedades e blocos init são executados na ordem em que aparecem. Referenciar uma propriedade antes de sua declaração pode resultar em valores inesperados ou nulos.\nConclusão e Próximos Passos Neste tutorial, você dominou os fundamentos de classes e objetos em Kotlin: declaração de classes, construtores primários e secundários, properties com getters e setters customizados, blocos init, companion objects e modificadores de visibilidade. Esses conceitos formam a base da programação orientada a objetos em Kotlin.\nO próximo passo é aprender sobre herança em Kotlin, onde você verá como criar hierarquias de classes usando open, override e classes abstratas. Também recomendamos estudar data classes, que geram automaticamente equals(), hashCode(), toString() e copy(). Com o domínio de classes e objetos, você está pronto para construir aplicações Kotlin bem estruturadas e de fácil manutenção.\n","permalink":"https://kotlin.dev.br/tutoriais/classes-e-objetos-kotlin/","summary":"\u003cp\u003eNeste tutorial, vamos explorar em profundidade o sistema de classes e objetos do Kotlin. Programação orientada a objetos (OOP) é um dos paradigmas mais utilizados no desenvolvimento de software, é o Kotlin oferece uma implementação moderna e concisa desses conceitos. Você aprenderá a declarar \u003ca href=\"/glossario/class/\"\u003eclasses\u003c/a\u003e, usar construtores primários e secundários, definir properties com getters e setters personalizados, trabalhar com init blocks, \u003ca href=\"/glossario/companion-object/\"\u003ecompanion objects\u003c/a\u003e e modificadores de visibilidade.\u003c/p\u003e\n\u003ch2 id=\"declaração-de-classes\"\u003eDeclaração de Classes\u003c/h2\u003e\n\u003cp\u003eEm Kotlin, classes são declaradas com a palavra-chave \u003ccode\u003eclass\u003c/code\u003e. A forma mais simples de criar uma classe não exige nenhum corpo — apenas o nome é suficiente. Quando a classe possui propriedades e métodos, o corpo é delimitado por chaves.\u003c/p\u003e","title":"Classes e Objetos em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Se você está começando no mundo da programação ou já possui experiência com outras linguagens e deseja aprender Kotlin, este guia completo foi feito especialmente para você. Kotlin é uma linguagem moderna, concisa e segura, desenvolvida pela JetBrains e oficialmente suportada pelo Google para desenvolvimento Android. Neste artigo, vamos explorar desde os conceitos mais básicos até recursos intermediários que farão você se sentir confiante para criar seus próprios projetos.\nO Que é Kotlin e Por Que Aprender? Kotlin é uma linguagem de programação estaticamente tipada que roda na JVM (Java Virtual Machine). Lançada oficialmente em 2016, ela rapidamente ganhou popularidade por oferecer uma sintaxe mais limpa e expressiva que Java, ao mesmo tempo em que mantém total interoperabilidade com o ecossistema Java existente.\nAs principais razões para aprender Kotlin incluem:\nConcisão: você escreve menos código para alcançar o mesmo resultado comparado a Java Segurança contra null: o sistema de tipos de Kotlin diferencia referências que podem ser null daquelas que não podem, eliminando grande parte dos NullPointerException Interoperabilidade: Kotlin funciona perfeitamente com bibliotecas e frameworks Java existentes Multiplataforma: com Kotlin Multiplatform, é possível compartilhar código entre Android, iOS, web e backend Suporte oficial do Google: desde 2019, Kotlin é a linguagem preferida para desenvolvimento Android Se você pretende trabalhar com desenvolvimento Android, backend com Spring Boot ou Ktor, ou até mesmo desenvolvimento multiplataforma, Kotlin é uma escolha estratégica e moderna. Para um panorama completo dos termos que usaremos, consulte nosso glossário de Kotlin.\nConfigurando o Ambiente de Desenvolvimento Antes de escrever sua primeira linha de código, é necessário configurar o ambiente. Existem algumas opções populares para trabalhar com Kotlin:\nIntelliJ IDEA é a IDE mais recomendada, pois é desenvolvida pela mesma empresa que criou Kotlin. A versão Community é gratuita e já inclui suporte completo à linguagem. Para instalar, basta acessar o site da JetBrains e baixar a versão adequada ao seu sistema operacional.\nAndroid Studio é a opção ideal se o seu foco é desenvolvimento mobile. Baseado no IntelliJ IDEA, ele já vem configurado com todas as ferramentas necessárias para criar aplicativos Android com Kotlin.\nPara testar código rapidamente sem instalar nada, você pode usar o Kotlin Playground disponível em play.kotlinlang.org, que permite escrever e executar código Kotlin diretamente no navegador.\nApós instalar sua IDE preferida, crie um novo projeto Kotlin e verifique se a versão do JDK está configurada corretamente (recomendamos JDK 17 ou superior). Com isso, você está pronto para começar a programar.\nSintaxe Básica e Variáveis A sintaxe de Kotlin é intuitiva e fácil de aprender. Vamos começar com o clássico \u0026ldquo;Hello World\u0026rdquo;:\nfun main() { println(\u0026#34;Olá, mundo!\u0026#34;) } Diferente de Java, não é necessário criar uma classe para executar um programa simples. A função main é o ponto de entrada da aplicação.\nDeclaração de Variáveis Kotlin oferece duas palavras-chave para declarar variáveis:\nval nome = \u0026#34;Kotlin Brasil\u0026#34; // Imutável (equivalente a final em Java) var idade = 5 // Mutável, pode ser reatribuída idade = 6 // OK // nome = \u0026#34;Outro\u0026#34; // Erro de compilacao! A recomendação é sempre preferir val sobre var. Variáveis imutáveis tornam o código mais previsível e menos propenso a bugs. O compilador de Kotlin também faz inferência de tipos automaticamente, então nem sempre é necessário declarar o tipo explicitamente. Porém, quando desejado, você pode fazer assim:\nval linguagem: String = \u0026#34;Kotlin\u0026#34; val versao: Double = 2.0 val ativa: Boolean = true Tipos Básicos Kotlin possui os seguintes tipos numéricos e textuais principais:\nTipo Descrição Exemplo Int Inteiro de 32 bits 42 Long Inteiro de 64 bits 100L Double Ponto flutuante de 64 bits 3.14 Float Ponto flutuante de 32 bits 2.5f Boolean Verdadeiro ou falso true String Cadeia de caracteres \u0026quot;texto\u0026quot; Char Caractere único 'A' Estruturas de Controle Kotlin oferece estruturas de controle familiares, mas com melhorias significativas em relação a outras linguagens.\nCondicionais com if/else Em Kotlin, if é uma expressão, ou seja, retorna um valor:\nval nota = 85 val resultado = if (nota \u0026gt;= 70) \u0026#34;Aprovado\u0026#34; else \u0026#34;Reprovado\u0026#34; println(resultado) // Aprovado Expressão when O when substitui o switch de Java e é muito mais poderoso:\nval diaSemana = 3 val nomeDia = when (diaSemana) { 1 -\u0026gt; \u0026#34;Segunda-feira\u0026#34; 2 -\u0026gt; \u0026#34;Terça-feira\u0026#34; 3 -\u0026gt; \u0026#34;Quarta-feira\u0026#34; 4 -\u0026gt; \u0026#34;Quinta-feira\u0026#34; 5 -\u0026gt; \u0026#34;Sexta-feira\u0026#34; 6 -\u0026gt; \u0026#34;Sábado\u0026#34; 7 -\u0026gt; \u0026#34;Domingo\u0026#34; else -\u0026gt; \u0026#34;Dia invalido\u0026#34; } println(nomeDia) // Quarta-feira Laços de Repetição // For loop com range for (i in 1..10) { println(i) } // For loop com step for (i in 0..20 step 2) { println(i) // 0, 2, 4, 6, ... } // While loop var contador = 0 while (contador \u0026lt; 5) { println(\u0026#34;Contagem: $contador\u0026#34;) contador++ } Funções em Kotlin Funções são blocos de código reutilizáveis e constituem a base de qualquer programa bem estruturado.\nfun saudacao(nome: String): String { return \u0026#34;Olá, $nome! Bem-vindo ao Kotlin Brasil.\u0026#34; } // Função com corpo de expressão (single-expression function) fun dobro(numero: Int): Int = numero * 2 // Função com parâmetros padrao fun criarUsuario(nome: String, idade: Int = 18, ativo: Boolean = true) { println(\u0026#34;Usuário: $nome, Idade: $idade, Ativo: $ativo\u0026#34;) } Os parâmetros padrão eliminam a necessidade de criar múltiplas sobrecargas de função, algo muito comum em Java. Além disso, Kotlin suporta argumentos nomeados, que tornam as chamadas de função mais legíveis:\ncriarUsuario(nome = \u0026#34;Ana\u0026#34;, idade = 25, ativo = true) criarUsuario(nome = \u0026#34;Carlos\u0026#34;) // Usa valores padrao para idade e ativo Para se aprofundar em funções avançadas, confira nosso guia de programação funcional em Kotlin.\nClasses e Orientação a Objetos Kotlin simplifica drasticamente a criação de classes comparado a Java:\nclass Pessoa(val nome: String, var idade: Int) { fun apresentar(): String { return \u0026#34;Meu nome é $nome e tenho $idade anos.\u0026#34; } } val pessoa = Pessoa(\u0026#34;Maria\u0026#34;, 30) println(pessoa.apresentar()) Data Classes As data classes são perfeitas para classes que servem principalmente para armazenar dados. Kotlin gera automaticamente os métodos equals(), hashCode(), toString(), copy() e componentN():\ndata class Produto( val id: Int, val nome: String, val preco: Double ) val produto = Produto(1, \u0026#34;Notebook\u0026#34;, 3500.0) println(produto) // Produto(id=1, nome=Notebook, preco=3500.0) val produtoAtualizado = produto.copy(preco = 3200.0) Null Safety Um dos recursos mais importantes de Kotlin é o sistema de null safety. Por padrão, variáveis não podem ser null:\nvar nome: String = \u0026#34;Kotlin\u0026#34; // nome = null // Erro de compilacao! var nomeNullable: String? = \u0026#34;Kotlin\u0026#34; nomeNullable = null // OK // Safe call operator println(nomeNullable?.length) // null (nao lança excecao) // Elvis operator val tamanho = nomeNullable?.length ?: 0 println(tamanho) // 0 Esse sistema elimina grande parte dos erros de NullPointerException que são tão comuns em Java, tornando seu código muito mais seguro e confiável em produção.\nColeções e Operações Funcionais Kotlin oferece uma API rica para trabalhar com coleções, distinguindo entre coleções mutáveis e imutáveis:\n// Lista imutável val frutas = listOf(\u0026#34;Maçã\u0026#34;, \u0026#34;Banana\u0026#34;, \u0026#34;Laranja\u0026#34;) // Lista mutável val numeros = mutableListOf(1, 2, 3) numeros.add(4) // Map val capitais = mapOf( \u0026#34;Brasil\u0026#34; to \u0026#34;Brasília\u0026#34;, \u0026#34;Argentina\u0026#34; to \u0026#34;Buenos Aires\u0026#34;, \u0026#34;Chile\u0026#34; to \u0026#34;Santiago\u0026#34; ) // Operações funcionais val pares = (1..20).filter { it % 2 == 0 } val quadrados = pares.map { it * it } val soma = quadrados.reduce { acc, valor -\u0026gt; acc + valor } println(\u0026#34;Pares: $pares\u0026#34;) println(\u0026#34;Quadrados: $quadrados\u0026#34;) println(\u0026#34;Soma: $soma\u0026#34;) As operações funcionais como filter, map, reduce, flatMap e groupBy são extremamente poderosas e permitem manipular dados de forma expressiva e concisa. Para entender como essas operações se conectam com programação reativa, confira nosso guia de Kotlin Flow.\nPróximos Passos e Recursos Recomendados Agora que você conhece os fundamentos de Kotlin, aqui estão os caminhos que você pode seguir:\nDesenvolvimento Android: comece com nosso guia de Kotlin para Android e explore o Jetpack Compose Desenvolvimento Backend: confira o guia de Kotlin para backend e aprenda sobre Ktor Multiplataforma: explore o Kotlin Multiplatform para compartilhar código entre plataformas Coroutines: domine a programação assíncrona com nosso guia de Coroutines Recomendamos também acompanhar nossos tutoriais práticos que cobrem projetos reais do início ao fim. Consulte o glossário sempre que encontrar um termo desconhecido.\nKotlin é uma linguagem que combina poder e simplicidade de uma forma única. Com prática consistente e os recursos certos, você estará construindo aplicações robustas em pouco tempo. Bem-vindo à comunidade Kotlin Brasil! E se quiser explorar outras linguagens modernas, conheça Go para sistemas backend escaláveis, Python para data science e automação e Rust para programação de sistemas com segurança.\n","permalink":"https://kotlin.dev.br/guias/guia-completo-kotlin/","summary":"\u003cp\u003eSe você está começando no mundo da programação ou já possui experiência com outras linguagens e deseja aprender Kotlin, este guia completo foi feito especialmente para você. Kotlin é uma linguagem moderna, concisa e segura, desenvolvida pela JetBrains e oficialmente suportada pelo Google para desenvolvimento Android. Neste artigo, vamos explorar desde os conceitos mais básicos até recursos intermediários que farão você se sentir confiante para criar seus próprios projetos.\u003c/p\u003e\n\u003ch2 id=\"o-que-é-kotlin-e-por-que-aprender\"\u003eO Que é Kotlin e Por Que Aprender?\u003c/h2\u003e\n\u003cp\u003eKotlin é uma linguagem de programação estaticamente tipada que roda na JVM (Java Virtual Machine). Lançada oficialmente em 2016, ela rapidamente ganhou popularidade por oferecer uma sintaxe mais limpa e expressiva que Java, ao mesmo tempo em que mantém total interoperabilidade com o ecossistema Java existente.\u003c/p\u003e","title":"Guia Completo de Kotlin para Iniciantes: Aprenda do Zero | Kotlin Brasil"},{"content":"Neste tutorial, vamos explorar em profundidade o sistema de funções do Kotlin. Funções são blocos de código reutilizáveis que realizam uma tarefa específica e são a base de qualquer programa. Você vai aprender a declarar funções com a palavra-chave fun, definir parâmetros e tipos de retorno, usar default parameters, named arguments, single-expression functions, vararg e funções locais. Ao final, você terá domínio completo sobre como criar e organizar funções em Kotlin.\nDeclarando Funções com fun Em Kotlin, toda função é declarada usando a palavra-chave fun. A estrutura básica inclui o nome da função, a lista de parâmetros entre parênteses e, opcionalmente, o tipo de retorno após dois-pontos. Se a função não retorna nenhum valor útil, o tipo de retorno é Unit, que pode ser omitido.\nfun saudacao() { println(\u0026#34;Olá, bem-vindo ao Kotlin Brasil!\u0026#34;) } fun somar(a: Int, b: Int): Int { return a + b } fun main() { saudacao() val resultado = somar(10, 20) println(\u0026#34;Soma: $resultado\u0026#34;) // Soma: 30 } Diferente de linguagens como Java, em Kotlin as funções não precisam estar dentro de uma classe. Você pode declarar funções no nível superior do arquivo, o que chamamos de funções top-level. Isso reduz a necessidade de criar classes utilitárias com métodos estáticos e torna o código mais direto e limpo.\nParâmetros e Tipos de Retorno Todo parâmetro em Kotlin precisa ter o tipo declarado explicitamente. Isso garante segurança de tipos em tempo de compilação. O tipo de retorno também deve ser declarado, exceto quando o compilador consegue inferi-lo automaticamente em single-expression functions.\nfun calcularDesconto(preco: Double, percentual: Double): Double { val desconto = preco * (percentual / 100) return preco - desconto } fun ehMaiorDeIdade(idade: Int): Boolean { return idade \u0026gt;= 18 } fun imprimirDetalhes(nome: String, idade: Int): Unit { println(\u0026#34;Nome: $nome, Idade: $idade\u0026#34;) } fun main() { println(calcularDesconto(100.0, 15.0)) // 85.0 println(ehMaiorDeIdade(21)) // true imprimirDetalhes(\u0026#34;Carlos\u0026#34;, 30) // Nome: Carlos, Idade: 30 } Observe que o tipo Unit é equivalente ao void do Java, mas em Kotlin ele é um tipo real. Quando o retorno é Unit, você pode omitir tanto a declaração do tipo quanto a instrução return.\nDefault Parameters (Parâmetros Padrão) Uma das funcionalidades mais práticas do Kotlin é a possibilidade de definir valores padrão para parâmetros. Isso elimina a necessidade de múltiplas sobrecargas de função, algo muito comum em Java.\nfun criarUsuario( nome: String, email: String, ativo: Boolean = true, papel: String = \u0026#34;usuario\u0026#34; ): String { return \u0026#34;Usuário: $nome | Email: $email | Ativo: $ativo | Papel: $papel\u0026#34; } fun main() { // Usando todos os parâmetros println(criarUsuario(\u0026#34;Ana\u0026#34;, \u0026#34;ana@email.com\u0026#34;, false, \u0026#34;admin\u0026#34;)) // Usando apenas os obrigatórios (ativo=true, papel=\u0026#34;usuario\u0026#34;) println(criarUsuario(\u0026#34;João\u0026#34;, \u0026#34;joao@email.com\u0026#34;)) // Misturando: passando ativo, mas usando papel padrao println(criarUsuario(\u0026#34;Maria\u0026#34;, \u0026#34;maria@email.com\u0026#34;, true)) } Com default parameters, você pode ter uma única função que atende a vários cenários de uso. Os parâmetros com valor padrão devem, em geral, ser colocados no final da lista de parâmetros, facilitando a chamada sem named arguments.\nNamed Arguments (Argumentos Nomeados) Named arguments permitem que você passe argumentos fora de ordem, referenciando-os pelo nome. Isso é especialmente útil em funções com muitos parâmetros ou quando vários parâmetros têm o mesmo tipo.\nfun configurarServidor( host: String = \u0026#34;localhost\u0026#34;, porta: Int = 8080, ssl: Boolean = false, timeout: Int = 30 ) { println(\u0026#34;Servidor: $host:$porta | SSL: $ssl | Timeout: ${timeout}s\u0026#34;) } fun main() { // Chamada tradicional configurarServidor(\u0026#34;meusite.com\u0026#34;, 443, true, 60) // Com named arguments - muito mais legível configurarServidor( host = \u0026#34;meusite.com\u0026#34;, porta = 443, ssl = true, timeout = 60 ) // Pulando parâmetros com valor padrao configurarServidor(ssl = true, timeout = 120) // Resultado: Servidor: localhost:8080 | SSL: true | Timeout: 120s } A combinação de default parameters com named arguments é extremamente poderosa. Ela permite criar APIs flexíveis e legíveis sem a complexidade de padrões como Builder.\nSingle-Expression Functions (Funções de Expressão Única) Quando uma função possui apenas uma expressão, você pode simplificar a sintaxe removendo as chaves e o return, usando o operador = diretamente. O compilador infere o tipo de retorno automaticamente.\n// Forma tradicional fun dobrar(valor: Int): Int { return valor * 2 } // Single-expression function fun dobrarSimplificado(valor: Int) = valor * 2 fun ehPar(numero: Int) = numero % 2 == 0 fun formatarNome(primeiro: String, ultimo: String) = \u0026#34;$primeiro $ultimo\u0026#34;.trim() fun maximo(a: Int, b: Int) = if (a \u0026gt; b) a else b fun main() { println(dobrarSimplificado(21)) // 42 println(ehPar(10)) // true println(formatarNome(\u0026#34;Kotlin\u0026#34;, \u0026#34;Brasil\u0026#34;)) // Kotlin Brasil println(maximo(15, 23)) // 23 } Single-expression functions são idiomáticas em Kotlin e usadas extensivamente no dia a dia. Elas tornam o código conciso sem sacrificar a legibilidade, especialmente para funções pequenas e auxiliares.\nVararg: Número Variável de Argumentos O modificador vararg permite que uma função receba um número variável de argumentos do mesmo tipo. Internamente, o Kotlin trata esses argumentos como um array.\nfun calcularMedia(vararg notas: Double): Double { if (notas.isEmpty()) return 0.0 return notas.sum() / notas.size } fun imprimirTodos(prefixo: String, vararg mensagens: String) { for (msg in mensagens) { println(\u0026#34;$prefixo: $msg\u0026#34;) } } fun main() { println(calcularMedia(7.5, 8.0, 9.2, 6.8)) // 7.875 println(calcularMedia(10.0, 9.5)) // 9.75 imprimirTodos(\u0026#34;LOG\u0026#34;, \u0026#34;Iniciando\u0026#34;, \u0026#34;Processando\u0026#34;, \u0026#34;Concluído\u0026#34;) // Passando um array com o operador spread (*) val valores = doubleArrayOf(8.0, 7.0, 9.0) println(calcularMedia(*valores)) // 8.0 } Quando você já tem um array e quer passá-lo para uma função vararg, use o operador spread (*). Note que só é possível ter um parâmetro vararg por função, e ele normalmente é o último parâmetro, embora possa estar em outra posição se os demais argumentos forem passados como named arguments.\nFunções Locais Kotlin permite declarar funções dentro de outras funções. Essas funções locais têm acesso às variáveis do escopo externo (closure) e são úteis para encapsular lógica auxiliar que não faz sentido expor fora da função principal.\nfun processarPedido(itens: List\u0026lt;String\u0026gt;, desconto: Double) { // Função local com acesso ao parâmetro \u0026#39;desconto\u0026#39; fun calcularPreco(precoBase: Double): Double { return precoBase * (1 - desconto / 100) } fun validarItem(item: String): Boolean { return item.isNotBlank() \u0026amp;\u0026amp; item.length \u0026gt; 2 } for (item in itens) { if (validarItem(item)) { val preco = calcularPreco(50.0) println(\u0026#34;Item: $item - Preço com desconto: R$${\u0026#34;%.2f\u0026#34;.format(preco)}\u0026#34;) } } } fun main() { val meusItens = listOf(\u0026#34;Camiseta\u0026#34;, \u0026#34;Calça\u0026#34;, \u0026#34;\u0026#34;, \u0026#34;Tênis\u0026#34;) processarPedido(meusItens, 10.0) } Funções locais são ideais quando você precisa reutilizar um trecho de código dentro de uma função, mas essa lógica não é relevante em nenhum outro contexto do programa. Elas ajudam a manter funções grandes organizadas sem poluir o escopo do arquivo.\nErros Comuns Esquecer o tipo de retorno em funções complexas. Em funções com múltiplas linhas, o Kotlin não infere o tipo de retorno. Você precisa declará-lo explicitamente. Single-expression functions são a exceção.\n// ERRO: funcoes com corpo em bloco precisam declarar o tipo de retorno // fun somar(a: Int, b: Int) { return a + b } // CORRETO fun somar(a: Int, b: Int): Int { return a + b } Confundir a posição do vararg. Se o vararg não for o último parâmetro, os demais argumentos devem ser passados com named arguments, o que frequentemente confunde iniciantes.\nNão aproveitar default parameters. Muitos desenvolvedores vindos de Java criam várias sobrecargas de funções, quando um único método com valores padrão resolveria o problema de forma mais elegante.\nUsar !! dentro de funções sem tratamento. Ao receber tipos nullable, evite forçar a conversão com !!. Prefira safe calls ou verificações explícitas.\nFunções muito longas. Se a função tem mais de 20-30 linhas, considere extrair partes dela em funções locais ou em funções separadas. Funções pequenas e focadas são mais fáceis de testar e manter.\nConclusão e Próximos Passos Neste tutorial, você aprendeu os fundamentos das funções em Kotlin: desde a declaração básica com fun até recursos avançados como default parameters, named arguments, single-expression functions, vararg e funções locais. Essas ferramentas tornam o Kotlin uma linguagem expressiva e produtiva para construir aplicações de qualquer porte.\nO próximo passo natural é explorar higher-order functions e lambdas, que levam o conceito de funções a um nível ainda mais poderoso. Também recomendamos estudar extension functions, que permitem adicionar funcionalidades a classes existentes sem herança. Com domínio completo de funções, você terá uma base sólida para avançar nos tutoriais sobre classes e objetos e programação orientada a objetos em Kotlin.\n","permalink":"https://kotlin.dev.br/tutoriais/funcoes-kotlin/","summary":"\u003cp\u003eNeste tutorial, vamos explorar em profundidade o sistema de funções do Kotlin. Funções são blocos de código reutilizáveis que realizam uma tarefa específica e são a base de qualquer programa. Você vai aprender a declarar funções com a palavra-chave \u003ca href=\"/glossario/fun/\"\u003efun\u003c/a\u003e, definir parâmetros e tipos de retorno, usar default parameters, named arguments, single-expression functions, vararg e funções locais. Ao final, você terá domínio completo sobre como criar e organizar funções em Kotlin.\u003c/p\u003e","title":"Funções em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Neste tutorial, você vai aprender a criar seu primeiro programa em Kotlin do absoluto zero. Vamos configurar o ambiente de desenvolvimento, entender a estrutura básica de um programa Kotlin e executar o clássico \u0026ldquo;Hello, World!\u0026rdquo;. Ao final, você terá uma base sólida para avançar nos próximos tutoriais da série.\nPor que Aprender Kotlin? Kotlin é uma linguagem de programação moderna, concisa e segura, criada pela JetBrains e oficialmente suportada pelo Google para desenvolvimento Android. Mas Kotlin vai muito além do mobile: você pode usá-la para desenvolvimento backend com frameworks como Ktor e Spring Boot, para aplicações desktop, e até para desenvolvimento multiplataforma com Kotlin Multiplatform.\nUma das maiores vantagens de Kotlin é a sua interoperabilidade com Java. Isso significa que você pode usar qualquer biblioteca Java existente diretamente no seu código Kotlin, sem nenhuma configuração especial. Além disso, Kotlin possui recursos modernos como null safety, coroutines para programação assíncrona, é uma sintaxe muito mais enxuta que Java.\nSe você vem de outras linguagens como Python, JavaScript ou Java, vai perceber que Kotlin combina o melhor de vários mundos: a segurança de tipos de Java, a concisão de Python e recursos funcionais inspirados em Scala e outras linguagens modernas.\nConfigurando o Ambiente de Desenvolvimento Antes de escrever qualquer código, precisamos configurar o ambiente. Existem várias formas de trabalhar com Kotlin, e vamos explorar as principais opções.\nOpção 1: IntelliJ IDEA (Recomendado) A forma mais prática de programar em Kotlin é usando o IntelliJ IDEA, a IDE criada pela mesma empresa que desenvolveu Kotlin. Você pode baixar a versão Community (gratuita) no site oficial da JetBrains.\nApós instalar o IntelliJ IDEA, siga estes passos:\nAbra o IntelliJ IDEA e clique em \u0026ldquo;New Project\u0026rdquo; Selecione \u0026ldquo;Kotlin\u0026rdquo; no menu lateral Escolha \u0026ldquo;JVM | IDEA\u0026rdquo; como template Defina o nome do projeto como \u0026ldquo;MeuPrimeiroKotlin\u0026rdquo; Clique em \u0026ldquo;Create\u0026rdquo; Opção 2: Kotlin Playground Online Se você quer começar imediatamente sem instalar nada, pode usar o Kotlin Playground diretamente no navegador acessando play.kotlinlang.org. Essa é uma excelente opção para testar pequenos trechos de código e experimentar a linguagem.\nOpção 3: Linha de Comando Você também pode instalar o compilador Kotlin via SDKMAN ou Homebrew:\n// Instalação via SDKMAN (Linux/Mac) // No terminal: sdk install kotlin // Após instalar, voce pode compilar e executar assim: // kotlinc hello.kt -include-runtime -d hello.jar // java -jar hello.jar Escrevendo o Primeiro Programa: Hello, World! Agora que o ambiente está configurado, vamos escrever nosso primeiro programa. Em Kotlin, o ponto de entrada de qualquer aplicação é a função main. Diferente de Java, você não precisa criar uma classe para isso.\nfun main() { println(\u0026#34;Olá, Mundo! Bem-vindo ao Kotlin!\u0026#34;) } Vamos entender cada parte deste código:\nfun: é a palavra-chave usada para declarar uma função em Kotlin. Toda função começa com fun. main: é o nome da função principal. O compilador Kotlin procura essa função como ponto de entrada do programa. (): os parênteses indicam que a função não recebe nenhum parâmetro. Em versões anteriores, era obrigatório declarar args: Array\u0026lt;String\u0026gt;, mas desde o Kotlin 1.3 isso é opcional. println(): é a função que imprime uma linha no console. Ela adiciona automaticamente uma quebra de linha ao final. Execute o programa e você verá a mensagem \u0026ldquo;Olá, Mundo! Bem-vindo ao Kotlin!\u0026rdquo; no console. Parabéns, você acabou de criar seu primeiro programa em Kotlin!\nExpandindo o Programa: Variáveis e Entrada do Usuário Agora vamos tornar o programa mais interessante adicionando variáveis e interação com o usuário.\nfun main() { println(\u0026#34;=== Meu Primeiro Programa em Kotlin ===\u0026#34;) println() // Declarando variáveis com val (imutável) e var (mutável) val linguagem = \u0026#34;Kotlin\u0026#34; val versao = \u0026#34;2.0\u0026#34; var contador = 0 println(\u0026#34;Bem-vindo ao curso de $linguagem $versao!\u0026#34;) println() // Pedindo o nome do usuário print(\u0026#34;Qual e o seu nome? \u0026#34;) val nome = readlnOrNull() ?: \u0026#34;Visitante\u0026#34; contador++ println(\u0026#34;Olá, $nome! Você e o visitante numero $contador.\u0026#34;) println() // Usando string templates mais elaborados val mensagem = \u0026#34;\u0026#34;\u0026#34; |Resumo do Programa: | Linguagem: $linguagem | Versão: $versao | Usuário: $nome | Execuções: $contador \u0026#34;\u0026#34;\u0026#34;.trimMargin() println(mensagem) // Operações basicas val anoAtual = 2025 val anoCriacao = 2011 println(\u0026#34;Kotlin existe há ${anoAtual - anoCriacao} anos!\u0026#34;) } Neste exemplo expandido, introduzimos vários conceitos importantes:\nval declara uma variável imutável (como final em Java). Uma vez atribuído o valor, ele não pode ser alterado. Prefira sempre usar val quando possível. var declara uma variável mutável, cujo valor pode ser alterado depois. String templates permitem inserir variáveis e expressões diretamente dentro de strings usando $variavel ou ${expressao}. readlnOrNull() lê uma linha da entrada padrão e retorna null se não houver entrada disponível. Operador Elvis ?: fornece um valor padrão quando a expressão à esquerda é null. Este é um recurso fundamental do sistema de null safety do Kotlin. Multiline strings (triple-quoted strings) permitem criar strings com várias linhas de forma legível, e trimMargin() remove os espaços à esquerda até o caractere |. Entendendo a Estrutura do Projeto Quando você cria um projeto Kotlin no IntelliJ IDEA, a estrutura de diretórios segue uma convenção padrão. O arquivo principal fica em src/main/kotlin/ e os arquivos de teste ficam em src/test/kotlin/. O arquivo de configuração do build system (Gradle) fica na raiz do projeto.\nÉ importante entender que Kotlin compila para bytecode da JVM por padrão, o que significa que seu código Kotlin roda na Java Virtual Machine exatamente como código Java. Isso garante compatibilidade com todo o ecossistema Java existente e performance de nível de produção.\nCada arquivo Kotlin tem a extensão .kt. Diferentemente de Java, o nome do arquivo não precisa corresponder ao nome da classe, e você pode ter múltiplas classes, funções e até variáveis de nível superior no mesmo arquivo.\nDicas e Erros Comuns Ao criar seus primeiros programas em Kotlin, fique atento aos seguintes pontos:\nEsquecer o fun antes de main: toda função precisa da palavra-chave fun. Sem ela, o compilador não reconhece a declaração.\nConfundir val e var: lembre-se que val é imutável. Se você tentar reatribuir um valor a uma variável val, o compilador vai gerar um erro. Use var apenas quando realmente precisar alterar o valor posteriormente.\nPonto e vírgula não é necessário: diferente de Java e C, Kotlin não exige ponto e vírgula no final das linhas. O compilador infere automaticamente o fim de cada instrução. Embora o ponto e vírgula seja permitido, ele é considerado não-idiomático.\nUsar println vs print: println adiciona uma quebra de linha no final, enquanto print não. Escolha conforme a necessidade do seu programa.\nNão usar a inferência de tipos: Kotlin possui um poderoso sistema de inferência de tipos. Você não precisa declarar o tipo explicitamente quando ele pode ser deduzido pelo compilador. Por exemplo, val nome = \u0026quot;Kotlin\u0026quot; já sabe que nome é do tipo String.\nIgnorar warnings do compilador: o compilador Kotlin é muito inteligente e gera avisos úteis. Sempre leia e corrija os warnings, pois eles frequentemente apontam para problemas reais no código.\nConclusão e Próximos Passos Parabéns por criar seu primeiro programa em Kotlin! Você aprendeu a configurar o ambiente de desenvolvimento, entendeu a estrutura básica de um programa, trabalhou com variáveis, string templates e entrada do usuário. Esses são os fundamentos sobre os quais todo o restante da linguagem é construído.\nKotlin é uma linguagem que recompensa o aprendizado gradual. Cada novo conceito se conecta naturalmente ao anterior, e a sintaxe concisa permite que você se concentre na lógica do programa em vez de ficar lutando com boilerplate desnecessário.\nNos próximos tutoriais, vamos aprofundar cada um dos conceitos que introduzimos aqui. Recomendo seguir esta ordem:\nVariáveis e Tipos de Dados — entenda em detalhes o sistema de tipos do Kotlin Estruturas Condicionais — aprenda a controlar o fluxo do seu programa com if, when e mais Funções em Kotlin — domine a criação de funções reutilizáveis e expressivas Continue praticando e experimentando no Kotlin Playground ou no IntelliJ IDEA. A melhor forma de aprender uma linguagem de programação é escrevendo código todos os dias, mesmo que sejam pequenos programas de prática. Até o próximo tutorial!\n","permalink":"https://kotlin.dev.br/tutoriais/primeiro-programa-kotlin/","summary":"\u003cp\u003eNeste tutorial, você vai aprender a criar seu primeiro programa em Kotlin do absoluto zero. Vamos configurar o ambiente de desenvolvimento, entender a estrutura básica de um programa Kotlin e executar o clássico \u0026ldquo;Hello, World!\u0026rdquo;. Ao final, você terá uma base sólida para avançar nos próximos tutoriais da série.\u003c/p\u003e\n\u003ch2 id=\"por-que-aprender-kotlin\"\u003ePor que Aprender Kotlin?\u003c/h2\u003e\n\u003cp\u003eKotlin é uma linguagem de programação moderna, concisa e segura, criada pela JetBrains e oficialmente suportada pelo Google para desenvolvimento Android. Mas Kotlin vai muito além do mobile: você pode usá-la para desenvolvimento backend com frameworks como Ktor e Spring Boot, para aplicações desktop, e até para desenvolvimento multiplataforma com Kotlin Multiplatform.\u003c/p\u003e","title":"Primeiro Programa em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"},{"content":"Banco Bradesco: um dos maiores bancos do mundo aposta em Kotlin O Banco Bradesco é uma das maiores instituições financeiras da América Latina e um dos bancos mais importantes do mundo. Com sede em Osasco, na região metropolitana de São Paulo, o Bradesco atende dezenas de milhões de clientes em todo o Brasil, oferecendo serviços bancários, seguros, previdência, capitalização e investimentos. Com quase 88 mil colaboradores, o banco é também um dos maiores empregadores privados do país — e sua área de tecnologia está no centro de uma transformação que coloca Kotlin como linguagem estratégica.\nA história do Bradesco se confunde com a história do sistema financeiro brasileiro. Fundado em 1943 em Marília, interior de São Paulo, o banco cresceu com uma filosofia de inclusão financeira, abrindo agências em regiões onde outros bancos não ousavam ir. Hoje, o Bradesco mantém uma das maiores redes de agências do Brasil e um dos apps bancários mais utilizados do país.\nAtuação e posição no mercado financeiro O Bradesco opera em praticamente todos os segmentos do mercado financeiro brasileiro:\nBanco de varejo: conta corrente, poupança, cartões de crédito, crédito pessoal e imobiliário para pessoas físicas Banco empresarial: serviços para empresas de todos os portes, incluindo capital de giro, câmbio e comércio exterior Seguros e previdência: através da Bradesco Seguros, maior grupo segurador do Brasil Investimentos: Bradesco BBI (banco de investimento) e Ágora Investimentos (plataforma de investimentos para pessoa física) Digital: Next (banco digital voltado para o público jovem, hoje integrado ao Bradesco) No cenário competitivo, o Bradesco disputa com Itaú, Banco do Brasil, Santander e Caixa Econômica entre os incumbentes, e enfrenta a pressão crescente de fintechs como Nubank, Inter e C6 Bank. Essa competição acelerou enormemente os investimentos em tecnologia e digitalização dos serviços.\nComo o Bradesco usa Kotlin A transformação digital do Bradesco é um dos maiores projetos de tecnologia em andamento no setor bancário mundial, dado o tamanho e a complexidade da operação. Kotlin desempenha um papel cada vez mais relevante nessa jornada.\nNo mobile, o aplicativo Bradesco para Android é um dos apps bancários mais baixados do Brasil e processa milhões de transações financeiras diariamente. A adoção de Kotlin no desenvolvimento Android do Bradesco acompanhou a recomendação oficial do Google e trouxe benefícios concretos: null safety para reduzir crashes em produção (cruciais quando se trata de dinheiro), coroutines para operações assíncronas como consultas de saldo e transferências, e uma sintaxe mais concisa que acelera o desenvolvimento de novas funcionalidades.\nO app do Bradesco vai além das operações bancárias tradicionais. Ele integra serviços de seguros, investimentos, consórcios e até a BIA (Bradesco Inteligência Artificial), a assistente virtual do banco que atende milhões de interações por mês. Toda essa complexidade funcional roda em um único app que precisa ser acessível, seguro e performático.\nNo backend, o Bradesco utiliza Kotlin em microsserviços que suportam a camada digital do banco. Novos serviços — especialmente aqueles ligados a APIs abertas (Open Finance), integração com o Pix e funcionalidades de banco digital — são frequentemente construídos em Kotlin sobre a JVM, aproveitando o vasto ecossistema de bibliotecas Java para o setor financeiro e a produtividade superior que Kotlin oferece.\nA migração de sistemas legados (muitos escritos em COBOL e Java antigo) para arquiteturas modernas também abre espaço para Kotlin. O banco adota uma estratégia de \u0026ldquo;estrangulamento\u0026rdquo; do legado, onde novas APIs em Kotlin encapsulam funcionalidades antigas e gradualmente as substituem.\nStack tecnológica e cultura de engenharia O stack de tecnologia do Bradesco reflete a complexidade de um banco centenário em plena transformação digital:\nBackend: Kotlin e Java com Spring Boot para serviços modernos, COBOL e mainframe IBM para o core bancário legado, integrações via APIs REST e mensageria Mobile: Kotlin para Android, Swift para iOS, com arquitetura modular para suportar a enorme quantidade de funcionalidades do app Cloud: estratégia multi-cloud com AWS, Azure e infraestrutura on-premise própria (requisito regulatório do Banco Central) Dados e IA: BIA (assistente virtual baseada em inteligência artificial), modelos de machine learning para análise de crédito, detecção de fraude e personalização de ofertas Segurança: criptografia de ponta, autenticação biométrica, tokens de segurança e monitoramento 24/7 de transações suspeitas A cultura de engenharia do Bradesco mistura a disciplina do setor bancário com a agilidade de uma empresa de tecnologia moderna. A área de TI do banco emprega milhares de profissionais e opera em squads ágeis organizados por produtos e jornadas do cliente. O banco investiu bilhões nos últimos anos em tecnologia e transformação digital.\nO Bradesco mantém o inovaBra, um hub de inovação que conecta o banco a startups, universidades e parceiros tecnológicos. Esse ecossistema de inovação permite que engenheiros do Bradesco experimentem com tecnologias emergentes em um ambiente mais flexível antes de incorporá-las aos produtos do banco.\nOportunidades de carreira no Bradesco Trabalhar na área de tecnologia do Bradesco é lidar com um dos ambientes computacionais mais complexos do Brasil. O banco processa bilhões de transações por ano, mantém sistemas que não podem ficar fora do ar e precisa atender a uma regulamentação bancária extremamente rigorosa. Cada linha de código que vai para produção tem um peso enorme.\nCom mais de 1.400 vagas tipicamente abertas, o Bradesco busca constantemente profissionais de tecnologia. Para devs Kotlin, as oportunidades se concentram em times de desenvolvimento mobile (app Bradesco, app Bradesco Seguros, app Ágora), backend de APIs digitais, Open Finance e produtos de banco digital.\nO pacote de benefícios é um dos mais completos do mercado: salário compatível com o setor bancário, participação nos lucros expressiva (PLR do setor bancário é historicamente generosa), plano de saúde e odontológico premium, previdência privada com contrapartida do banco, vale-refeição e alimentação, auxílio creche e programas de qualidade de vida. A estabilidade de uma instituição financeira desse porte é outro fator atrativo.\nA sede de tecnologia fica na Cidade de Deus, em Osasco, um complexo corporativo enorme com infraestrutura completa. O banco também possui centros de tecnologia em Alphaville e Curitiba, além de opções de trabalho remoto para determinadas posições.\nPor que um dev Kotlin deveria considerar o Bradesco O Bradesco oferece algo que poucas empresas no Brasil podem oferecer: a chance de usar Kotlin para impactar diretamente a vida financeira de dezenas de milhões de brasileiros. O app que você vai ajudar a construir está no bolso de pessoas de todas as classes sociais e regiões do país.\nDo ponto de vista técnico, o setor bancário traz desafios que elevam o nível de qualquer engenheiro: requisitos extremos de segurança, disponibilidade de cinco noves (99,999%), regulamentação do Banco Central, conformidade com padrões internacionais e a necessidade de integrar sistemas modernos com legado de décadas. Resolver esses problemas com Kotlin vai torná-lo um profissional mais completo e preparado.\nA estabilidade financeira e os benefícios do setor bancário, combinados com o investimento crescente em modernização tecnológica, fazem do Bradesco uma opção atraente para quem quer usar Kotlin em um contexto onde qualidade e confiabilidade são inegociáveis.\nSaiba mais sobre vagas Visite o portal oficial do Bradesco: https://banco.bradesco\n","permalink":"https://kotlin.dev.br/empresas/banco-bradesco/","summary":"\u003ch2 id=\"banco-bradesco-um-dos-maiores-bancos-do-mundo-aposta-em-kotlin\"\u003eBanco Bradesco: um dos maiores bancos do mundo aposta em Kotlin\u003c/h2\u003e\n\u003cp\u003eO Banco Bradesco é uma das maiores instituições financeiras da América Latina e um dos bancos mais importantes do mundo. Com sede em Osasco, na região metropolitana de São Paulo, o Bradesco atende dezenas de milhões de clientes em todo o Brasil, oferecendo serviços bancários, seguros, previdência, capitalização e investimentos. Com quase 88 mil colaboradores, o banco é também um dos maiores empregadores privados do país — e sua área de tecnologia está no centro de uma transformação que coloca Kotlin como linguagem estratégica.\u003c/p\u003e","title":"Banco Bradesco — Empresa que Usa Kotlin no Brasil"},{"content":"Claro: A Gigante das Telecomunicações que Aposta em Kotlin Fundada em 2003, a Claro se tornou uma das operadoras de telecomunicações mais relevantes da América Latina. No Brasil, a empresa oferece um portfólio completo de serviços que inclui telefonia móvel e fixa, internet banda larga via fibra óptica, televisão por assinatura e soluções empresariais de conectividade. Sediada em São Paulo, a Claro faz parte do conglomerado América Móvil e conta com aproximadamente 37 mil colaboradores dedicados a manter e expandir uma infraestrutura que conecta milhões de brasileiros todos os dias.\nA operação da Claro é verdadeiramente nacional. Das capitais às cidades do interior, a empresa leva conectividade a uma parcela significativa da população brasileira. Essa capilaridade exige não apenas torres e cabos, mas uma infraestrutura digital sofisticada capaz de gerenciar planos, cobranças, atendimento e entretenimento para uma base de clientes que não para de crescer.\nAtuação no Brasil e Relevância no Mercado O setor de telecomunicações brasileiro é marcado por alta competitividade, regulamentação rigorosa da Anatel e demandas crescentes dos consumidores por qualidade e velocidade. Nesse cenário, a Claro se posiciona como uma das líderes, investindo continuamente na expansão da cobertura 5G e na melhoria da experiência digital de seus clientes.\nCom mais de 2.400 vagas de tecnologia anunciadas regularmente, fica evidente que a Claro trata o desenvolvimento de software como pilar estratégico do negócio. A empresa entende que a diferenciação no mercado de telecom deixou de ser apenas sobre infraestrutura física — hoje, a experiência digital que o cliente tem ao interagir com a operadora é tão importante quanto a qualidade do sinal.\nA Claro também expandiu sua atuação para o mercado de streaming e conteúdo digital, oferecendo plataformas integradas aos seus planos de TV e internet. Essa diversificação aumenta ainda mais a demanda por engenheiros de software capazes de construir e manter sistemas complexos e de alta disponibilidade.\nKotlin na Engenharia da Claro A adoção de Kotlin na Claro reflete uma estratégia de modernização tecnológica que vem ganhando força nos últimos anos. No desenvolvimento Android, Kotlin é a linguagem padrão para os aplicativos que a empresa disponibiliza aos seus clientes. O principal deles, o app de autoatendimento, precisa lidar com funcionalidades como consulta de consumo de dados, pagamento de faturas, ativação de serviços e suporte via chat — tudo isso de forma rápida e intuitiva.\nNo backend, a Claro utiliza Kotlin com Spring Boot para construir microsserviços que fazem parte de uma arquitetura distribuída. Esses serviços são responsáveis por operações críticas como provisionamento de linhas, processamento de pagamentos e integração com sistemas de parceiros. A interoperabilidade de Kotlin com Java é particularmente valiosa nesse contexto, pois permite que a empresa evolua sua codebase gradualmente, sem precisar reescrever tudo do zero.\nKotlin Coroutines também são utilizadas para lidar com operações assíncronas em sistemas que precisam responder a milhares de requisições simultâneas. Quando um cliente acessa o app para verificar seu saldo ou mudar de plano, a resposta precisa ser quase instantânea — e a programação assíncrona eficiente que Kotlin oferece ajuda a garantir essa experiência.\nA empresa também investe em Kotlin Multiplatform para compartilhar lógica de negócios entre plataformas Android e iOS, reduzindo duplicação de código e acelerando o tempo de entrega de novas funcionalidades.\nTecnologias e Cultura de Engenharia O ecossistema tecnológico da Claro é vasto. Além de Kotlin e Java, a empresa trabalha com Python para ciência de dados, Swift para desenvolvimento iOS, JavaScript e TypeScript para aplicações web, e Go para serviços de alta performance. A infraestrutura é gerenciada com Kubernetes, Terraform e serviços de cloud pública, garantindo escalabilidade e resiliência.\nA cultura de engenharia na Claro privilegia a autonomia dos times. Squads multifuncionais são responsáveis por produtos ou domínios específicos, desde o aplicativo de autoatendimento até sistemas internos de gestão de rede. Cada squad tem liberdade para tomar decisões técnicas dentro de guidelines arquiteturais definidas por capítulos de engenharia.\nA empresa promove internamente meetups técnicos, sessões de code review colaborativo e programas de mentoria. Engenheiros seniores têm a oportunidade de participar de comunidades de prática onde compartilham aprendizados sobre Kotlin, arquitetura de microsserviços, observabilidade e outras disciplinas técnicas. Essa troca de conhecimento constante eleva o nível técnico de toda a organização.\nO uso de práticas como CI/CD, testes automatizados e feature flags é padrão nos times de engenharia. Deploys acontecem várias vezes por semana, e a cultura de monitoramento com ferramentas como Datadog e Grafana permite que problemas sejam identificados e resolvidos rapidamente.\nCarreira e Benefícios na Claro A Claro é um dos maiores empregadores de tecnologia do Brasil, e as oportunidades para desenvolvedores Kotlin são abundantes. As posições variam desde desenvolvedor mobile Android até engenheiro de plataforma, passando por cargos de tech lead e arquiteto de soluções. A empresa valoriza tanto profissionais experientes quanto talentos em início de carreira, mantendo programas de estágio e trainee com foco em tecnologia.\nO ambiente de trabalho oferece modelo híbrido para a maioria das posições de tecnologia, com escritórios modernos em São Paulo equipados para colaboração presencial quando necessário. O pacote de benefícios inclui assistência médica e odontológica, vale-refeição e alimentação, seguro de vida, previdência privada e descontos em produtos Claro — um benefício que os colaboradores costumam elogiar bastante.\nQuanto ao crescimento profissional, a Claro oferece trilhas de carreira bem definidas, tanto para quem deseja seguir o caminho técnico quanto para quem prefere migrar para gestão. Avaliações de desempenho semestrais e planos de desenvolvimento individual ajudam os colaboradores a traçar objetivos claros e alcançáveis.\nPor Que Desenvolvedores Kotlin Devem Olhar para a Claro A Claro oferece algo que poucas empresas no Brasil podem proporcionar: a chance de trabalhar em sistemas que impactam dezenas de milhões de pessoas diariamente. Para um desenvolvedor Kotlin, isso significa enfrentar desafios reais de escalabilidade, performance e confiabilidade — problemas que vão muito além do que se encontra em projetos de menor porte.\nA diversidade de projetos também é um atrativo. Você pode trabalhar no app Android que está no bolso de milhões de brasileiros, nos microsserviços de backend que processam bilhões de transações por mês, ou em ferramentas internas que otimizam a operação da rede. Essa variedade permite que desenvolvedores Kotlin ampliem seu repertório técnico sem precisar trocar de empresa.\nA estabilidade financeira da Claro, aliada ao investimento contínuo em tecnologia, garante que os projetos de modernização não serão abandonados no meio do caminho. Quando a empresa decide adotar Kotlin como linguagem estratégica, ela investe de verdade — em treinamento, em contratação e em ferramentas que suportem a adoção em larga escala.\nComo se Candidatar Acesse o site da Claro em claro.com.br para conhecer mais sobre a empresa, ou visite diretamente o perfil no LinkedIn para conferir as vagas abertas. O processo seletivo geralmente inclui triagem de currículo, entrevista com RH, desafio técnico envolvendo Kotlin e entrevista com o time de engenharia. Demonstrar familiaridade com Kotlin idiomático, coroutines e boas práticas de arquitetura Android pode ser um diferencial importante na seleção.\n","permalink":"https://kotlin.dev.br/empresas/claro/","summary":"\u003ch2 id=\"claro-a-gigante-das-telecomunicações-que-aposta-em-kotlin\"\u003eClaro: A Gigante das Telecomunicações que Aposta em Kotlin\u003c/h2\u003e\n\u003cp\u003eFundada em 2003, a Claro se tornou uma das operadoras de telecomunicações mais relevantes da América Latina. No Brasil, a empresa oferece um portfólio completo de serviços que inclui telefonia móvel e fixa, internet banda larga via fibra óptica, televisão por assinatura e soluções empresariais de conectividade. Sediada em São Paulo, a Claro faz parte do conglomerado América Móvil e conta com aproximadamente 37 mil colaboradores dedicados a manter e expandir uma infraestrutura que conecta milhões de brasileiros todos os dias.\u003c/p\u003e","title":"Claro — Empresa que Usa Kotlin no Brasil"},{"content":"Claro Brasil: Telecomunicações e Inovação com Kotlin A Claro Brasil é uma das maiores operadoras de telecomunicações do país, oferecendo serviços de telefonia móvel, internet banda larga, TV por assinatura e soluções corporativas para milhões de brasileiros. Com sede em São Paulo e presença em todo o território nacional, a empresa faz parte do grupo América Móvil, controlado pelo empresário mexicano Carlos Slim, e se consolidou como referência em conectividade e infraestrutura digital no mercado brasileiro.\nCom mais de 42 mil colaboradores, a Claro Brasil movimenta uma operação de escala impressionante. A empresa atende desde o consumidor final que precisa de um plano de celular até grandes corporações que dependem de redes dedicadas e soluções de cloud. Essa diversidade de atuação exige um ecossistema tecnológico robusto, e é justamente aí que linguagens modernas como Kotlin entram em cena.\nPosição no Mercado Brasileiro de Telecom O mercado de telecomunicações brasileiro é um dos maiores do mundo, e a Claro Brasil disputa a liderança com poucas concorrentes de peso. A empresa se destaca especialmente em internet móvel e fixa, tendo investido bilhões de reais na expansão da rede 5G pelo país. Essa corrida tecnológica não se limita à infraestrutura física — ela exige plataformas digitais sofisticadas para gerenciar a experiência de milhões de usuários.\nA transformação digital na Claro Brasil é visível em produtos como o app Minha Claro, que permite aos clientes gerenciar seus planos, consumir conteúdos e resolver demandas sem precisar ligar para o call center. Manter esse tipo de aplicação funcionando de maneira fluida para uma base tão grande de usuários é um desafio de engenharia de software que poucos times no Brasil enfrentam.\nComo a Claro Brasil Utiliza Kotlin Kotlin desempenha um papel estratégico na stack tecnológica da Claro Brasil, especialmente no desenvolvimento de aplicativos Android. O app Minha Claro, utilizado por milhões de clientes diariamente, precisa de performance, estabilidade e uma experiência de uso impecável — características que Kotlin entrega naturalmente com sua sintaxe concisa e segurança contra null pointer exceptions.\nAlém do desenvolvimento mobile, a Claro Brasil também adota Kotlin em seus serviços de backend. A migração de sistemas legados para arquiteturas baseadas em microsserviços é uma realidade na empresa, e Kotlin, rodando sobre a JVM, permite que equipes aproveitem todo o ecossistema Java existente enquanto escrevem código mais limpo e produtivo. Frameworks como Spring Boot com Kotlin são utilizados para construir APIs que alimentam desde sistemas internos de gestão até plataformas voltadas ao consumidor final.\nA adoção de Kotlin também se estende a projetos de automação e integração de sistemas. Em uma operação do tamanho da Claro Brasil, automatizar processos de provisionamento de rede, billing e atendimento ao cliente é essencial, e Kotlin se mostra uma escolha eficiente para scripts e ferramentas internas que precisam ser confiáveis e fáceis de manter.\nStack Tecnológica e Cultura de Engenharia A Claro Brasil opera com uma stack tecnológica diversificada, compatível com a complexidade de seus serviços. Além de Kotlin, a empresa trabalha com Java, Python, Swift para iOS, e diversas tecnologias de infraestrutura como Kubernetes, Docker e serviços de cloud computing. Bancos de dados relacionais e NoSQL convivem no ecossistema, atendendo diferentes necessidades de armazenamento e consulta de dados em tempo real.\nA cultura de engenharia na Claro Brasil valoriza a inovação contínua. Times multidisciplinares trabalham com metodologias ágeis, e a empresa investe em programas de capacitação para manter seus profissionais atualizados. Hackathons internos, comunidades de prática e eventos de tecnologia fazem parte do dia a dia, criando um ambiente onde engenheiros podem experimentar novas tecnologias e propor melhorias nos produtos existentes.\nA escala da operação também proporciona desafios técnicos únicos. Lidar com picos de tráfego durante eventos como Black Friday ou lançamentos de novos planos exige sistemas resilientes e bem arquitetados. Para os desenvolvedores Kotlin, isso significa trabalhar com concorrência, coroutines e padrões de design que garantam alta disponibilidade mesmo sob pressão extrema.\nOportunidades de Carreira na Claro Brasil Com quase 500 vagas de tecnologia abertas regularmente, a Claro Brasil é um dos maiores empregadores de desenvolvedores no país. As oportunidades vão desde posições para desenvolvedores Android com experiência em Kotlin até engenheiros de backend, arquitetos de software e especialistas em DevOps. A empresa também mantém programas de estágio e trainee voltados para jovens talentos que estão começando na área.\nO pacote de benefícios da Claro Brasil é competitivo e inclui plano de saúde, vale-refeição, participação nos lucros e, naturalmente, descontos em produtos e serviços da operadora. O modelo de trabalho é flexível, com muitas posições oferecendo a possibilidade de trabalho remoto ou híbrido, o que amplia o alcance para profissionais de todo o Brasil.\nTrabalhar na Claro Brasil significa ter impacto direto na vida de milhões de pessoas. Cada feature lançada no app, cada melhoria de performance em um microsserviço, cada otimização no sistema de billing afeta a experiência de uma base de clientes gigantesca. Para quem gosta de ver o resultado do seu trabalho em larga escala, esse é um diferencial difícil de encontrar em outras empresas.\nPor Que um Desenvolvedor Kotlin Deve Considerar a Claro Brasil Se você é desenvolvedor Kotlin e está em busca de novos desafios, a Claro Brasil oferece uma combinação rara de escala, impacto e diversidade técnica. A empresa está em plena transformação digital, o que significa que não faltam projetos greenfield onde Kotlin é a linguagem principal. Ao mesmo tempo, existe o desafio de modernizar sistemas legados, uma oportunidade para quem gosta de refatoração e melhoria contínua.\nO networking dentro da empresa também é um ponto forte. Com mais de 42 mil colaboradores e um time de tecnologia expressivo, você terá contato com profissionais de diferentes especialidades — desde engenheiros de rede até cientistas de dados — ampliando sua visão sobre como tecnologia e negócio se conectam no setor de telecom.\nA Claro Brasil também proporciona estabilidade. Como parte de um grupo internacional sólido, a empresa oferece segurança profissional ao mesmo tempo em que investe pesado em inovação. Para desenvolvedores Kotlin que querem crescer na carreira, a Claro Brasil apresenta um caminho claro de evolução, desde posições técnicas especializadas até cargos de liderança em engenharia.\nSaiba Mais e Candidate-se Para conhecer as vagas abertas e saber mais sobre como é trabalhar na Claro Brasil, acesse o site oficial em claro.com.br ou confira o perfil da empresa no LinkedIn. As oportunidades são atualizadas frequentemente, e o processo seletivo costuma incluir entrevistas técnicas onde seu conhecimento em Kotlin será valorizado.\n","permalink":"https://kotlin.dev.br/empresas/claro-brasil/","summary":"\u003ch2 id=\"claro-brasil-telecomunicações-e-inovação-com-kotlin\"\u003eClaro Brasil: Telecomunicações e Inovação com Kotlin\u003c/h2\u003e\n\u003cp\u003eA Claro Brasil é uma das maiores operadoras de telecomunicações do país, oferecendo serviços de telefonia móvel, internet banda larga, TV por assinatura e soluções corporativas para milhões de brasileiros. Com sede em São Paulo e presença em todo o território nacional, a empresa faz parte do grupo América Móvil, controlado pelo empresário mexicano Carlos Slim, e se consolidou como referência em conectividade e infraestrutura digital no mercado brasileiro.\u003c/p\u003e","title":"Claro Brasil — Empresa que Usa Kotlin no Brasil"},{"content":"Dasa: Tecnologia e Kotlin Transformando a Saúde no Brasil A Dasa é a maior rede integrada de saúde do Brasil, reunindo hospitais, laboratórios de diagnóstico, centros de medicina preventiva e operações de gestão de saúde sob um mesmo ecossistema. Fundada em 1999 em São Paulo, a empresa cresceu exponencialmente por meio de aquisições estratégicas e hoje conta com mais de 32 mil colaboradores distribuídos por todo o país. Marcas como Delboni Auriemo, Lavoisier, Salomão Zoppi e Alta Diagnósticos fazem parte do grupo, atendendo milhões de pacientes anualmente.\nA missão da Dasa vai além de oferecer exames e consultas — a empresa se posiciona como uma plataforma de saúde integrada, onde dados clínicos, inteligência artificial e tecnologia de ponta convergem para oferecer cuidado personalizado e preditivo. Nesse contexto, o desenvolvimento de software não é um suporte ao negócio, mas o próprio motor que viabiliza a visão de futuro da companhia.\nPresença e Relevância no Mercado de Saúde O setor de saúde no Brasil é um dos maiores do mundo, e a Dasa ocupa uma posição de destaque absoluto. A empresa processa centenas de milhões de exames por ano, opera dezenas de hospitais e mantém uma rede de atendimento que vai do Rio Grande do Sul ao Amazonas. Esse volume coloca a Dasa entre as maiores empresas de saúde do planeta, não apenas do Brasil.\nA transformação digital na saúde brasileira acelerou enormemente nos últimos anos, impulsionada pela pandemia e pela crescente expectativa dos pacientes por experiências digitais fluidas. A Dasa respondeu a essa demanda investindo pesado em tecnologia: aplicativos para agendamento de exames, portais de resultados online, teleconsultas e sistemas de prontuário eletrônico integrado. Cada um desses produtos depende de software bem construído, escalável e seguro.\nCom mais de 1.600 vagas de tecnologia abertas regularmente, a Dasa demonstra que entende a importância de atrair e reter talentos de engenharia de software. A empresa compete diretamente com fintechs e big techs pelo mesmo pool de desenvolvedores, e tem investido em benefícios, cultura e projetos desafiadores para se diferenciar.\nComo a Dasa Utiliza Kotlin Na Dasa, Kotlin é utilizado em múltiplas frentes do desenvolvimento de software. O aplicativo mobile da empresa, que permite aos pacientes agendar exames, acessar resultados e gerenciar seu histórico de saúde, é desenvolvido nativamente para Android com Kotlin. A experiência do paciente nesse app é crítica — ninguém quer enfrentar bugs ou lentidão quando está preocupado com um resultado de exame. Por isso, a escolha de Kotlin, com sua segurança de tipos e tratamento elegante de null safety, faz toda a diferença.\nNo backend, Kotlin é empregado na construção de microsserviços que compõem a plataforma de saúde integrada da Dasa. Esses serviços são responsáveis por processar dados clínicos, integrar sistemas de laboratório com hospitais, gerenciar agendamentos e alimentar dashboards de business intelligence. A interoperabilidade com o ecossistema Java permite que a Dasa modernize gradualmente seus sistemas legados sem interromper operações críticas.\nKotlin Coroutines desempenham um papel importante em serviços que precisam lidar com alta concorrência, como o sistema de entrega de resultados de exames. Quando milhares de pacientes acessam seus resultados simultaneamente, o backend precisa responder de forma eficiente, e as coroutines do Kotlin oferecem um modelo de programação assíncrona que é tanto performático quanto legível.\nA Dasa também explora Kotlin para ferramentas de automação e pipelines de dados. Em uma empresa que gera petabytes de dados clínicos, ter ferramentas robustas para ETL, validação de dados e integração entre sistemas é fundamental. Kotlin se encaixa bem nesse cenário por sua tipagem forte e expressividade.\nStack Tecnológica e Cultura de Engenharia A stack da Dasa é moderna e diversificada. Além de Kotlin e Java, a empresa utiliza Python para projetos de machine learning e ciência de dados, TypeScript para aplicações web, e Swift para o app iOS. A infraestrutura roda em cloud, com uso extensivo de AWS e serviços gerenciados como EKS, RDS, SQS e Lambda. Kubernetes orquestra os microsserviços, e Terraform garante a infraestrutura como código.\nA cultura de engenharia da Dasa se organiza em torno de squads autônomos, cada um responsável por um domínio do negócio. Existe um forte incentivo à experimentação e à adoção de novas tecnologias, desde que alinhadas com as necessidades do produto. Code reviews são práticas obrigatórias, e a empresa mantém padrões de qualidade que incluem cobertura mínima de testes e análise estática de código.\nUm aspecto diferenciador da engenharia na Dasa é o impacto humano do trabalho. Cada sistema construído ou melhorado tem potencial de afetar diretamente a vida de pacientes — desde a velocidade com que um resultado crítico é entregue até a precisão de um sistema de triagem automatizada. Essa consciência permeia a cultura dos times e adiciona uma camada de propósito que vai além do código.\nA empresa também investe em eventos internos de tecnologia, programas de mentoria e parcerias com universidades. Engenheiros são incentivados a participar de conferências e a contribuir com a comunidade tech, inclusive a comunidade Kotlin no Brasil.\nOportunidades de Carreira na Dasa A Dasa oferece um espectro amplo de oportunidades para profissionais de tecnologia. Desenvolvedores Kotlin podem encontrar vagas em times de desenvolvimento mobile, engenharia de backend, plataforma de dados e infraestrutura. Posições de tech lead e staff engineer também são recorrentes, oferecendo caminhos de crescimento para quem deseja aprofundar sua expertise técnica sem necessariamente migrar para gestão.\nO modelo de trabalho é predominantemente híbrido, com escritórios em São Paulo e outras capitais. Os benefícios incluem assistência médica premium — como esperado de uma empresa de saúde —, vale-refeição, auxílio home office, programas de bem-estar e acesso facilitado a exames e consultas na rede Dasa, um benefício que os colaboradores valorizam especialmente.\nA empresa também mantém programas de desenvolvimento contínuo, incluindo bolsas para cursos, certificações e pós-graduação. Para desenvolvedores Kotlin que desejam se especializar em áreas como health tech, data engineering ou arquitetura de sistemas distribuídos, a Dasa oferece um terreno fértil de aprendizado.\nPor Que Desenvolvedores Kotlin Devem Considerar a Dasa Trabalhar na Dasa significa aplicar suas habilidades em Kotlin para resolver problemas que realmente importam. A saúde é um dos setores onde tecnologia tem o maior potencial de impacto positivo, e a Dasa está na vanguarda dessa transformação no Brasil. Se você quer que seu código faça diferença na vida das pessoas — e não estamos falando de forma figurativa —, a Dasa é uma escolha que vale a pena investigar.\nA escala da operação também é atraente. Estamos falando de centenas de milhões de exames processados, milhões de pacientes atendidos e sistemas que precisam funcionar com confiabilidade extrema. Para quem curte desafios de engenharia de sistemas distribuídos, alta disponibilidade e processamento massivo de dados, a Dasa entrega tudo isso em um contexto onde cada milissegundo importa de verdade.\nPor fim, a Dasa está em um momento de crescimento acelerado na área de tecnologia. A empresa reconhece que precisa de software de classe mundial para competir no mercado de saúde, e está disposta a investir em pessoas, ferramentas e processos para chegar lá. Para desenvolvedores Kotlin ambiciosos, esse é o tipo de momento ideal para embarcar.\nCandidate-se Explore as oportunidades na Dasa acessando dasa.com.br ou acompanhe as vagas pelo LinkedIn da empresa. O processo seletivo costuma envolver entrevistas técnicas com foco em design de sistemas, resolução de problemas e conhecimento prático de Kotlin e seu ecossistema.\n","permalink":"https://kotlin.dev.br/empresas/dasa/","summary":"\u003ch2 id=\"dasa-tecnologia-e-kotlin-transformando-a-saúde-no-brasil\"\u003eDasa: Tecnologia e Kotlin Transformando a Saúde no Brasil\u003c/h2\u003e\n\u003cp\u003eA Dasa é a maior rede integrada de saúde do Brasil, reunindo hospitais, laboratórios de diagnóstico, centros de medicina preventiva e operações de gestão de saúde sob um mesmo ecossistema. Fundada em 1999 em São Paulo, a empresa cresceu exponencialmente por meio de aquisições estratégicas e hoje conta com mais de 32 mil colaboradores distribuídos por todo o país. Marcas como Delboni Auriemo, Lavoisier, Salomão Zoppi e Alta Diagnósticos fazem parte do grupo, atendendo milhões de pacientes anualmente.\u003c/p\u003e","title":"Dasa — Empresa que Usa Kotlin no Brasil"},{"content":"Hospital Israelita Albert Einstein: Excelência em Saúde Impulsionada por Kotlin O Hospital Israelita Albert Einstein é uma das instituições de saúde mais respeitadas do mundo. Localizado em São Paulo, o Einstein é reconhecido internacionalmente por sua excelência clínica, pesquisa médica de ponta e adoção pioneira de tecnologias na área da saúde. Com mais de 40 mil colaboradores, a instituição vai muito além de um hospital — é um ecossistema que engloba ensino, pesquisa, consultoria em gestão de saúde e operação de unidades públicas em parceria com o governo.\nA reputação do Einstein atrai não apenas pacientes de todo o Brasil e do exterior, mas também profissionais de tecnologia que buscam trabalhar em projetos de alto impacto. A instituição entende que o futuro da medicina passa pela transformação digital e tem investido de forma consistente em equipes de engenharia de software para construir soluções que melhorem o atendimento ao paciente e a eficiência operacional.\nO Einstein no Cenário da Saúde Brasileira No ranking dos melhores hospitais da América Latina, o Einstein aparece consistentemente entre os primeiros colocados. A instituição é referência em procedimentos complexos, transplantes, oncologia e cardiologia, e também se destaca na telemedicina e saúde digital. Nos últimos anos, o Einstein expandiu significativamente sua presença, inaugurando novas unidades e assumindo a gestão de hospitais públicos em São Paulo.\nO compromisso com inovação é parte do DNA da instituição. O Einstein mantém um centro de inovação dedicado a explorar tecnologias emergentes como inteligência artificial aplicada a diagnósticos, wearables para monitoramento remoto de pacientes e plataformas digitais que conectam pacientes e médicos de forma transparente. Cada uma dessas iniciativas depende de engenharia de software sólida.\nCom mais de 1.200 vagas de tecnologia abertas regularmente, o Einstein compete pelos mesmos talentos que startups e big techs. A diferença está no propósito: no Einstein, cada linha de código tem potencial de melhorar ou até salvar a vida de alguém.\nKotlin no Ecossistema Tecnológico do Einstein O Einstein adota Kotlin como linguagem estratégica em seu desenvolvimento de software, tanto em aplicações mobile quanto em sistemas de backend. O aplicativo do Einstein para pacientes, disponível para Android, permite agendamento de consultas e exames, acesso a resultados laboratoriais, teleconsultas e gerenciamento do histórico médico. Construído com Kotlin nativo, o app precisa oferecer uma experiência impecável, já que os pacientes frequentemente o utilizam em momentos de ansiedade e precisam de respostas claras e rápidas.\nNo lado do servidor, Kotlin é utilizado para desenvolver microsserviços que integram diferentes sistemas hospitalares. O ambiente de TI de um hospital do porte do Einstein é notoriamente complexo: sistemas de prontuário eletrônico, equipamentos de diagnóstico por imagem, laboratórios automatizados, farmácias e sistemas de faturamento precisam conversar entre si em tempo real. Kotlin, com sua robustez sobre a JVM e suporte nativo a programação assíncrona via coroutines, é uma escolha natural para esses desafios de integração.\nA instituição também utiliza Kotlin em projetos de automação hospitalar. Sistemas que automatizam a distribuição de medicamentos, o agendamento de salas cirúrgicas e a triagem de pacientes no pronto-socorro se beneficiam da expressividade e segurança que Kotlin oferece. Em ambientes críticos como esses, bugs podem ter consequências sérias, e a tipagem forte de Kotlin ajuda a prevenir erros que linguagens mais permissivas deixariam passar.\nAlém disso, o Einstein explora Kotlin em iniciativas de inteligência artificial e machine learning, especialmente na construção de APIs e serviços que expõem modelos de IA para uso clínico. Quando um algoritmo de IA precisa analisar uma imagem de raio-X e retornar um resultado em segundos, o serviço que orquestra essa operação precisa ser confiável, rápido e fácil de monitorar — características que Kotlin entrega com qualidade.\nStack Tecnológica e Cultura de Engenharia A stack tecnológica do Einstein reflete a diversidade de seus projetos. Kotlin e Java dominam o backend e o desenvolvimento Android, enquanto Swift é utilizado para iOS. Python é a linguagem preferida para projetos de data science e machine learning. A infraestrutura é baseada em cloud computing, com uso de containers Docker orquestrados por Kubernetes, e a empresa utiliza práticas maduras de DevOps com pipelines de CI/CD automatizados.\nA cultura de engenharia no Einstein se diferencia pelo peso dado à segurança e à conformidade regulatória. Sistemas de saúde precisam atender a regulamentações rigorosas da LGPD, da ANVISA e de normas internacionais como HL7 e FHIR para interoperabilidade de dados clínicos. Os engenheiros de software do Einstein trabalham com essas restrições diariamente, o que exige um nível de cuidado e atenção a detalhes que não é comum em outros setores.\nOs times se organizam em squads ágeis, com cerimônias regulares de sprint planning, retrospectivas e demos. A colaboração entre engenheiros de software e profissionais de saúde é frequente e enriquecedora — não é raro que um desenvolvedor participe de reuniões com médicos para entender como determinada funcionalidade impacta o fluxo clínico. Essa proximidade com o usuário final dá um significado especial ao trabalho técnico.\nO Einstein também incentiva a participação em conferências, publicação de artigos técnicos e contribuições para projetos open source. A instituição tem parcerias com universidades e centros de pesquisa, o que abre portas para projetos inovadores que combinam medicina e tecnologia de forma única.\nOportunidades de Carreira e Benefícios O Einstein oferece um ambiente de trabalho que combina a seriedade de uma instituição médica de referência com a dinâmica de uma empresa de tecnologia moderna. As vagas para desenvolvedores Kotlin abrangem desde posições junior até cargos de staff engineer e arquiteto de software. A instituição também contrata tech leads, product managers e especialistas em segurança da informação, criando um ecossistema completo para quem trabalha com tecnologia.\nOs benefícios são um dos pontos fortes de trabalhar no Einstein. Além do pacote tradicional com assistência médica — naturalmente de alto nível — e vale-refeição, a instituição oferece acesso a programas de saúde e bem-estar, assistência psicológica, auxílio educação e descontos em serviços médicos. O modelo de trabalho é híbrido para a maioria das posições de tecnologia, e os escritórios em São Paulo contam com infraestrutura moderna e confortável.\nA estabilidade da instituição é outro fator relevante. Diferente de startups que dependem de rodadas de investimento, o Einstein tem uma operação financeiramente saudável e um crescimento consistente. Para profissionais que buscam segurança sem abrir mão de inovação, essa combinação é rara e valiosa.\nPor Que Desenvolvedores Kotlin Devem Considerar o Einstein Poucas empresas no Brasil oferecem a combinação de propósito, desafio técnico e prestígio que o Einstein proporciona. Trabalhar aqui significa que seu código Kotlin pode, literalmente, ajudar a salvar vidas. O sistema de triagem que você otimiza pode acelerar o atendimento de um paciente em estado crítico. O microsserviço que você constrói pode garantir que um resultado de exame chegue ao médico a tempo de mudar uma decisão clínica.\nDo ponto de vista técnico, o Einstein oferece problemas de engenharia sofisticados: integração de sistemas heterogêneos, processamento de dados sensíveis em tempo real, construção de plataformas de telemedicina com requisitos rigorosos de disponibilidade e segurança. Para desenvolvedores Kotlin que buscam crescer tecnicamente, esses desafios são um trampolim para um nível de expertise diferenciado.\nO prestígio da marca Einstein também é um ativo para sua carreira. Ter o Einstein no currículo abre portas tanto no setor de health tech quanto em tecnologia de maneira geral, sinalizando que você trabalhou em um ambiente de alta exigência e alto impacto.\nSaiba Mais e Candidate-se Para explorar as oportunidades de carreira no Einstein, acesse einstein.br ou confira as vagas no LinkedIn da instituição. O processo seletivo costuma incluir avaliação técnica, entrevista comportamental e conversa com o time — uma boa preparação em Kotlin, arquitetura de microsserviços e boas práticas de engenharia de software fará diferença.\n","permalink":"https://kotlin.dev.br/empresas/einstein-hospital-israelita/","summary":"\u003ch2 id=\"hospital-israelita-albert-einstein-excelência-em-saúde-impulsionada-por-kotlin\"\u003eHospital Israelita Albert Einstein: Excelência em Saúde Impulsionada por Kotlin\u003c/h2\u003e\n\u003cp\u003eO Hospital Israelita Albert Einstein é uma das instituições de saúde mais respeitadas do mundo. Localizado em São Paulo, o Einstein é reconhecido internacionalmente por sua excelência clínica, pesquisa médica de ponta e adoção pioneira de tecnologias na área da saúde. Com mais de 40 mil colaboradores, a instituição vai muito além de um hospital — é um ecossistema que engloba ensino, pesquisa, consultoria em gestão de saúde e operação de unidades públicas em parceria com o governo.\u003c/p\u003e","title":"Einstein Hospital Israelita — Empresa que Usa Kotlin no Brasil"},{"content":"Embraer: a terceira maior fabricante de aviões do mundo constrói software com Kotlin A Embraer é a terceira maior fabricante de jatos comerciais do planeta e o maior orgulho da engenharia brasileira no cenário global. Sediada em São José dos Campos, no interior de São Paulo, a empresa projeta e fabrica aeronaves para aviação comercial, executiva, defesa e segurança. Com quase 25 mil colaboradores, a Embraer é uma potência industrial que está se tornando, cada vez mais, uma potência de software — e Kotlin faz parte dessa história.\nQuando pensamos em Embraer, pensamos em aviões. Mas a verdade é que um avião moderno é essencialmente um computador que voa. O volume de software embarcado em uma aeronave moderna é enorme, e ao redor dele existe um ecossistema ainda maior de sistemas de suporte, manutenção, operação e serviços digitais. É nesse ecossistema adjacente que Kotlin ganha espaço.\nO que a Embraer faz e sua relevância global A Embraer atua em quatro segmentos principais:\nAviação Comercial: a família E-Jets (E175, E190, E195-E2) é referência mundial no segmento de jatos regionais, com mais de 1.800 aeronaves entregues a mais de 100 companhias aéreas em 70 países. O E195-E2, apelidado de \u0026ldquo;Profit Hunter\u0026rdquo;, é uma das aeronaves mais eficientes da sua categoria.\nAviação Executiva: sob a marca Phenom e Praetor, a Embraer fabrica jatos executivos premiados que competem globalmente com Bombardier, Gulfstream e Dassault. O Phenom 300 é o jato leve mais vendido do mundo há mais de uma década.\nDefesa e Segurança: a Embraer fornece aeronaves militares como o KC-390 (cargueiro tático), sistemas de vigilância e soluções de defesa para as Forças Armadas brasileiras e de outros países.\nEve Air Mobility: subsidiária focada em mobilidade aérea urbana, desenvolvendo eVTOLs (veículos elétricos de decolagem e pouso vertical) — os famosos \u0026ldquo;carros voadores\u0026rdquo;. A Eve é listada na NYSE e representa o futuro da mobilidade urbana.\nComo a Embraer usa Kotlin O uso de Kotlin na Embraer está concentrado nos sistemas digitais que orbitam ao redor da operação aeronáutica — não no software embarcado das aeronaves em si (que segue padrões de certificação como DO-178C e usa linguagens como Ada e C).\nNo desenvolvimento mobile, Kotlin é utilizado em aplicativos Android voltados para pilotos, mecânicos de manutenção e operadores de companhias aéreas. Imagine um app que permite ao piloto consultar manuais técnicos, planos de voo e informações operacionais da aeronave no tablet, ou um app que guia o técnico de manutenção por procedimentos de inspeção passo a passo com checklists digitais e integração com sensores da aeronave. Esses aplicativos exigem funcionamento offline confiável (nem sempre há Wi-Fi no hangar ou na pista), interfaces claras e segurança de dados rigorosa.\nNo backend, a Embraer utiliza Kotlin para construir microsserviços que sustentam suas plataformas digitais de serviços. O portal de suporte ao cliente, os sistemas de gestão de peças de reposição, as plataformas de dados de operação de frotas e os dashboards de manutenção preditiva são exemplos de sistemas que se beneficiam da produtividade e segurança que Kotlin oferece.\nA Embraer também emprega Kotlin no desenvolvimento de ferramentas internas de engenharia: sistemas de gestão de configuração de aeronaves, automação de processos de certificação e plataformas de colaboração entre equipes de projeto distribuídas globalmente.\nCom a Eve Air Mobility, há uma frente completamente nova de software sendo construída — desde o sistema de gerenciamento de tráfego aéreo urbano (UATM) até os aplicativos de reserva e operação dos eVTOLs. Esse é um terreno fértil para tecnologias modernas como Kotlin.\nStack tecnológica e cultura de engenharia O ecossistema tecnológico da Embraer é singular no Brasil:\nSoftware de engenharia: Catia, Siemens NX e ferramentas proprietárias para projeto e simulação de aeronaves Backend digital: Kotlin e Java com Spring Boot, Python para análise de dados e machine learning, microsserviços em containers Mobile: Kotlin para Android, Swift para iOS, com foco em apps para operação e manutenção aeronáutica Cloud e IoT: AWS para plataformas digitais, coleta de dados de sensores de aeronaves em voo (milhares de parâmetros por segundo) Dados e IA: manutenção preditiva baseada em dados de voo, digital twins de aeronaves, otimização de processos de manufatura Segurança: padrões aeronáuticos internacionais de cybersegurança, dados de operação de aeronaves tratados com rigor extremo A cultura de engenharia da Embraer é marcada pelo rigor e pela excelência. Na indústria aeronáutica, não existe \u0026ldquo;deploy and fix later\u0026rdquo; — tudo precisa funcionar da primeira vez. Essa mentalidade permeia mesmo os times de software que não trabalham diretamente com sistemas embarcados em aeronaves. O resultado é um padrão de qualidade de código e de testes que vai além do que a maioria das empresas de software pratica.\nAo mesmo tempo, a Embraer é surpreendentemente inovadora. A empresa foi uma das primeiras do setor aeronáutico a investir pesado em digital twins, manutenção preditiva baseada em IA e mobilidade aérea urbana. Há uma tensão produtiva entre o rigor aeronáutico e a vontade de inovar que cria um ambiente de trabalho estimulante.\nOportunidades de carreira e vida em São José dos Campos A principal base de operações da Embraer fica em São José dos Campos, cidade do Vale do Paraíba paulista com excelente qualidade de vida, custo de vida inferior a São Paulo e um ecossistema de tecnologia e inovação robusto (abriga também o ITA, INPE e diversas empresas de tecnologia). A empresa também mantém operações em Gavião Peixoto (SP), onde ficam as linhas de montagem, e escritórios em diversas cidades do mundo.\nCom mais de 2.100 vagas tipicamente abertas, a Embraer contrata para posições que vão de engenharia de software a engenharia aeronáutica. Para desenvolvedores Kotlin, as oportunidades estão em times de plataformas digitais, aplicativos de operação e manutenção, serviços conectados e na Eve Air Mobility.\nO pacote de benefícios inclui plano de saúde e odontológico, vale-refeição e alimentação, previdência privada, participação nos resultados, transporte fretado (de São Paulo a SJC), Gympass e programas de desenvolvimento. A Embraer tem parceria com o ITA e outras instituições para programas de pós-graduação e especialização.\nPor que um dev Kotlin deveria olhar para a Embraer A Embraer oferece algo que nenhuma startup ou big tech pode oferecer: a chance de escrever software que orbita ao redor de máquinas que voam. Cada app, cada microsserviço e cada plataforma que você construir com Kotlin estará conectado a uma das indústrias mais exigentes e fascinantes do mundo.\nPara quem busca propósito no trabalho, a Embraer entrega isso de sobra. Contribuir para a aviação brasileira, ajudar a manter aeronaves voando com segurança e participar do desenvolvimento dos \u0026ldquo;carros voadores\u0026rdquo; da Eve são oportunidades que vão muito além de otimizar métricas de conversão.\nO rigor da indústria aeronáutica vai torná-lo um engenheiro melhor. Trabalhar em um ambiente onde qualidade não é opcional, onde testes são levados a sério e onde a mentalidade de segurança é cultural vai elevar o seu padrão profissional de forma permanente. E se além de tudo isso você pode usar Kotlin, melhor ainda.\nConfira as vagas Acesse o site da Embraer e explore as oportunidades: https://embraer.com\n","permalink":"https://kotlin.dev.br/empresas/embraer/","summary":"\u003ch2 id=\"embraer-a-terceira-maior-fabricante-de-aviões-do-mundo-constrói-software-com-kotlin\"\u003eEmbraer: a terceira maior fabricante de aviões do mundo constrói software com Kotlin\u003c/h2\u003e\n\u003cp\u003eA Embraer é a terceira maior fabricante de jatos comerciais do planeta e o maior orgulho da engenharia brasileira no cenário global. Sediada em São José dos Campos, no interior de São Paulo, a empresa projeta e fabrica aeronaves para aviação comercial, executiva, defesa e segurança. Com quase 25 mil colaboradores, a Embraer é uma potência industrial que está se tornando, cada vez mais, uma potência de software — e Kotlin faz parte dessa história.\u003c/p\u003e","title":"Embraer — Empresa que Usa Kotlin no Brasil"},{"content":"Globo: o maior grupo de mídia da América Latina investe em Kotlin A Globo é o maior conglomerado de mídia e entretenimento do Brasil e um dos maiores do mundo. Dona da TV Globo, do Globoplay, do portal g1, do ge (Globo Esporte) e de dezenas de outras marcas, a empresa alcança praticamente todos os lares brasileiros. Com mais de 26 mil colaboradores, a Globo vive um momento de transformação digital profunda — e Kotlin é uma das tecnologias que sustentam essa transição do broadcast tradicional para o streaming e o digital.\nO que muita gente não percebe é que por trás das novelas, telejornais e transmissões esportivas existe uma operação de tecnologia gigantesca. A Globo não é apenas uma emissora de TV; é, cada vez mais, uma empresa de tecnologia que produz conteúdo.\nAtuação e posição no mercado brasileiro A Globo domina o cenário de mídia brasileiro de forma singular. A TV Globo é líder absoluta em audiência na TV aberta. O Globoplay, plataforma de streaming da empresa, compete com Netflix, Amazon Prime Video e Disney+ pelo público brasileiro, com a vantagem de oferecer conteúdo ao vivo (incluindo a programação da TV Globo) e produções originais exclusivas.\nNo digital, o grupo mantém os portais mais acessados do Brasil: g1 (notícias), ge (esportes), gshow (entretenimento), Tech Tudo (tecnologia) e diversos outros. A soma de audiência digital da Globo a coloca entre os maiores publishers de conteúdo do mundo.\nA empresa também é protagonista no mercado de publicidade digital brasileiro, com plataformas programáticas proprietárias que monetizam esse tráfego massivo. No segmento de áudio, a Globo opera estações de rádio e plataformas de podcast que complementam o ecossistema de conteúdo.\nComo a Globo utiliza Kotlin A adoção de Kotlin na Globo acompanha a transformação digital da empresa. No desenvolvimento mobile, Kotlin é a linguagem principal dos aplicativos Android do grupo — e são muitos: Globoplay, g1, ge, Globo Esporte, Cartola FC, entre outros. Cada um desses apps tem milhões de usuários ativos e exigências específicas de performance e experiência.\nO Globoplay, em particular, é um caso interessante de uso de Kotlin no Android. O app precisa lidar com streaming de vídeo ao vivo e sob demanda, downloads para assistir offline, múltiplos perfis de usuário, recomendações personalizadas e integração com Chromecast e outros dispositivos. As coroutines do Kotlin são fundamentais para orquestrar essas operações assíncronas complexas sem comprometer a fluidez da interface.\nNo backend, a Globo utiliza Kotlin em microsserviços que suportam a plataforma de streaming, o sistema de gerenciamento de conteúdo (CMS) e as APIs que alimentam os portais de notícias. A capacidade de processar eventos em tempo real é crítica — pense em uma notícia de última hora que precisa aparecer no g1, no app e na TV simultaneamente, ou em um gol durante uma partida que precisa atualizar o placar no ge e disparar notificações push para milhões de dispositivos.\nA Globo também investe em Kotlin para ferramentas de automação de produção de conteúdo, incluindo sistemas de transcodificação de vídeo, metadatação automática e fluxos de trabalho editorial.\nStack tecnológica e cultura de engenharia A Globo mantém uma das operações de tecnologia mais sofisticadas do Brasil:\nBackend: Kotlin e Java com Spring Boot, Go para serviços de alta performance, Python para pipelines de dados e machine learning Mobile: Kotlin para Android, Swift para iOS, com arquiteturas modulares que permitem reuso entre os diversos apps do grupo Streaming: infraestrutura proprietária de CDN e transcodificação de vídeo, capaz de sustentar milhões de streams simultâneos durante grandes eventos (final do BBB, jogos da Seleção) Cloud e infraestrutura: combinação de cloud pública (AWS, GCP) com infraestrutura on-premise para cargas de trabalho específicas de broadcast Dados e IA: modelos de recomendação de conteúdo, análise de audiência em tempo real, detecção automática de cenas para geração de highlights esportivos A cultura de engenharia da Globo é marcada pela intersecção única entre tecnologia e conteúdo. Engenheiros trabalham lado a lado com jornalistas, produtores e equipes criativas. Isso cria um ambiente onde o impacto do trabalho técnico é visível de forma imediata — o código que você escreve pode ser visto por milhões de pessoas na mesma noite.\nA empresa mantém uma comunidade técnica interna ativa, com tech talks regulares, capítulos de engenharia por área de especialidade e hackathons. A Globo também contribui para a comunidade open source e frequentemente publica artigos técnicos sobre os desafios de operar mídia em escala.\nOportunidades de carreira e ambiente de trabalho A sede de tecnologia da Globo fica no Rio de Janeiro, com presença também em São Paulo. O ambiente é um misto único de empresa de tecnologia e de entretenimento — não é incomum cruzar com atores nos corredores ou acompanhar a gravação de um programa ao lado do escritório de engenharia.\nA empresa oferece plano de saúde e odontológico, vale-refeição e alimentação, previdência privada, participação nos resultados, Gympass e programas de bem-estar. Um diferencial são os benefícios ligados ao universo Globo, como acesso ao Globoplay e ingressos para eventos e gravações.\nPara desenvolvedores, a Globo oferece trilhas de carreira técnica que vão de engenheiro júnior até posições de arquiteto e principal engineer. A empresa investe em formação por meio de parcerias com plataformas de aprendizado, budget para conferências e um programa estruturado de mentoria.\nO volume de vagas gira em torno de 200 posições abertas em tecnologia, o que reflete uma seleção mais criteriosa e equipes relativamente estáveis. Para devs Kotlin, as oportunidades se concentram em times de apps Android (Globoplay e portais), backend de streaming e microsserviços de conteúdo.\nPor que um dev Kotlin deveria considerar a Globo A Globo oferece algo que nenhuma outra empresa de tecnologia no Brasil pode oferecer: o casamento entre engenharia de software de ponta e a produção de conteúdo que molda a cultura do país. Se você é dev Kotlin, vai trabalhar em apps usados diariamente por uma parcela significativa da população brasileira.\nOs desafios técnicos são reais e empolgantes: streaming de vídeo em escala massiva, apps Android que precisam funcionar perfeitamente em milhares de modelos de dispositivos, backends que processam eventos em tempo real para dezenas de milhões de usuários simultâneos. Tudo isso em uma empresa que combina a estabilidade de um grupo consolidado com a mentalidade de inovação de uma empresa nativa digital.\nSe você quer que seu trabalho com Kotlin tenha impacto cultural além do impacto técnico, a Globo é o lugar certo.\nJunte-se ao time Confira as vagas abertas no portal de carreiras da Globo: https://vempraglobo.g.globo\n","permalink":"https://kotlin.dev.br/empresas/globo/","summary":"\u003ch2 id=\"globo-o-maior-grupo-de-mídia-da-américa-latina-investe-em-kotlin\"\u003eGlobo: o maior grupo de mídia da América Latina investe em Kotlin\u003c/h2\u003e\n\u003cp\u003eA Globo é o maior conglomerado de mídia e entretenimento do Brasil e um dos maiores do mundo. Dona da TV Globo, do Globoplay, do portal g1, do ge (Globo Esporte) e de dezenas de outras marcas, a empresa alcança praticamente todos os lares brasileiros. Com mais de 26 mil colaboradores, a Globo vive um momento de transformação digital profunda — e Kotlin é uma das tecnologias que sustentam essa transição do broadcast tradicional para o streaming e o digital.\u003c/p\u003e","title":"Globo — Empresa que Usa Kotlin no Brasil"},{"content":"Grupo Boticário: O Gigante da Beleza que Respira Tecnologia e Kotlin O Grupo Boticário é o maior conglomerado de beleza do Brasil e um dos maiores do mundo. Sediado em Curitiba, no Paraná, o grupo reúne marcas icônicas como O Boticário, Eudora, Quem Disse Berenice?, Vult, Beleza na Web e Australian Gold. Com mais de 47 mil colaboradores e presença em mais de 15 países, a empresa é muito mais do que uma fabricante de cosméticos — é uma potência de tecnologia e inovação que utiliza software de ponta para conectar produtos a consumidores em escala massiva.\nO que muita gente não sabe é que o Grupo Boticário é também uma das maiores empresas de tecnologia do Brasil. Com mais de 8 mil vagas abertas regularmente — muitas delas na área tech —, a empresa mantém um dos times de engenharia mais robustos do país. Essa aposta em tecnologia é parte de uma estratégia clara: em um mercado de beleza cada vez mais digital e competitivo, vence quem consegue oferecer a melhor experiência ao consumidor, tanto na loja física quanto no e-commerce.\nPresença no Mercado e Estratégia Digital O Grupo Boticário opera a maior rede de franquias de beleza do mundo, com milhares de lojas espalhadas pelo Brasil. Além das lojas físicas, a empresa investiu pesado em canais digitais: e-commerce próprio, marketplace, vendas por redes sociais e programas de revendedores digitais. Essa estratégia omnichannel exige uma infraestrutura tecnológica capaz de integrar estoque, logística, precificação, promoções e atendimento ao cliente de forma transparente.\nO programa de fidelidade do grupo, o Boti Club, é um dos maiores do varejo brasileiro, com dezenas de milhões de membros. Gerenciar esse programa — com suas regras de pontuação, ofertas personalizadas e comunicações segmentadas — é um desafio de engenharia de dados e software que poucos times no Brasil enfrentam. A personalização da experiência do consumidor, alimentada por algoritmos de recomendação e machine learning, é outra frente onde a tecnologia do Grupo Boticário se destaca.\nA empresa também é referência em sustentabilidade e responsabilidade social no setor de beleza, e utiliza tecnologia para rastrear a cadeia de suprimentos, medir o impacto ambiental de seus produtos e garantir práticas éticas de produção.\nKotlin no Grupo Boticário Kotlin é uma peça central na estratégia de desenvolvimento de software do Grupo Boticário. No mobile, os aplicativos Android das marcas do grupo — incluindo o app de compras do O Boticário e o app para revendedoras Eudora — são desenvolvidos com Kotlin nativo. Esses apps precisam entregar uma experiência premium que reflita o posicionamento das marcas: interface fluida, carregamento rápido de catálogos com milhares de produtos, integração com programas de fidelidade e checkout sem fricção.\nO backend do Grupo Boticário é onde Kotlin realmente brilha em escala. A empresa opera uma plataforma de e-commerce própria que precisa suportar picos brutais de tráfego durante eventos como Dia das Mães, Black Friday e Natal — datas em que o setor de beleza tem demanda explosiva. Microsserviços escritos em Kotlin com Spring Boot e Ktor processam pedidos, gerenciam estoque em tempo real e orquestram a logística de entrega para milhões de clientes.\nKotlin Coroutines são amplamente utilizadas nos serviços que precisam de alta concorrência. O sistema de recomendação de produtos, por exemplo, consulta múltiplas fontes de dados simultaneamente para sugerir produtos personalizados para cada cliente. Fazer isso de forma eficiente para milhões de usuários simultâneos requer programação assíncrona bem feita, e Kotlin torna isso natural e elegante.\nA empresa também utiliza Kotlin em pipelines de dados e ferramentas internas. O time de engenharia de dados do Grupo Boticário é um dos mais sofisticados do varejo brasileiro, e Kotlin é utilizado para construir componentes de ETL, validação de dados e integrações entre sistemas de vendas, estoque e CRM.\nTecnologias e Cultura de Engenharia O Grupo Boticário trabalha com uma stack moderna que inclui Kotlin, Java, TypeScript, Python e Go. A infraestrutura é cloud-native, com uso intensivo de Google Cloud Platform e AWS. Kubernetes é o orquestrador padrão para microsserviços, e a empresa adota práticas maduras de Infrastructure as Code com Terraform e Pulumi. Bancos de dados incluem PostgreSQL, MongoDB, Redis e BigQuery para análises em larga escala.\nA cultura de engenharia no Grupo Boticário é frequentemente elogiada por quem trabalha ou já trabalhou lá. A empresa investe em um modelo organizacional moderno, com tribos e squads inspirados no modelo Spotify, mas adaptados à realidade do negócio. Cada squad tem autonomia para escolher as melhores ferramentas e abordagens para seus problemas, dentro de um framework arquitetural que garante consistência e interoperabilidade.\nO Grupo Boticário promove ativamente o compartilhamento de conhecimento. Tech talks semanais, hackathons trimestrais, comunidades de prática por linguagem e tecnologia, e um programa de guild system permitem que engenheiros aprendam uns com os outros continuamente. A empresa também patrocina a participação em conferências nacionais e internacionais, incluindo eventos focados em Kotlin e JVM.\nO ambiente de trabalho é reconhecido por premiações como Great Place to Work, e a empresa se orgulha de manter uma cultura inclusiva e diversa. Os escritórios em Curitiba e São Paulo são modernos e projetados para colaboração, com espaços abertos, salas de foco e áreas de descompressão.\nCarreira e Benefícios O Grupo Boticário oferece um dos pacotes mais competitivos do mercado brasileiro para profissionais de tecnologia. Além de salários alinhados com o mercado, os benefícios incluem PLR expressiva, assistência médica e odontológica, vale-refeição e alimentação, auxílio home office, desconto em produtos do grupo — algo que os colaboradores adoram — e programas de desenvolvimento profissional que incluem bolsas de estudo e verba para cursos e certificações.\nAs oportunidades para desenvolvedores Kotlin são variadas: desde posições de desenvolvedor mobile Android até engenheiros de backend, engenheiros de plataforma, tech leads e arquitetos de software. A empresa também contrata engenheiros de dados, SREs e profissionais de segurança da informação. O modelo de trabalho é predominantemente remoto ou híbrido, o que permite que profissionais de qualquer região do Brasil participem do time.\nA trilha de carreira no Grupo Boticário é bem estruturada, com níveis claros desde junior até principal engineer, passando por senior, staff e tech lead. A empresa valoriza tanto o crescimento no track técnico quanto no gerencial, oferecendo opções reais para quem prefere continuar codando ao invés de gerenciar pessoas.\nPor Que Desenvolvedores Kotlin Devem Olhar para o Grupo Boticário O Grupo Boticário oferece uma combinação difícil de encontrar no mercado: escala massiva, marca forte, cultura de engenharia madura e impacto real no negócio. Para desenvolvedores Kotlin, isso se traduz em projetos desafiadores onde a linguagem é usada de forma estratégica — não como um experimento pontual, mas como a espinha dorsal de sistemas que processam milhões de transações e atendem dezenas de milhões de consumidores.\nO fato de a empresa estar sediada em Curitiba, com opção de trabalho remoto, também é atraente para quem quer fugir do eixo São Paulo-Rio sem abrir mão de trabalhar em projetos de primeira linha. E para quem está em São Paulo, a empresa mantém escritórios na capital paulista também.\nA solidez financeira do Grupo Boticário garante estabilidade em investimentos de longo prazo em tecnologia. Quando a empresa decide apostar em Kotlin, essa aposta vem acompanhada de recursos para treinamento, contratação e evolução da stack. Para quem quer construir carreira com Kotlin em uma empresa que leva tecnologia a sério, o Grupo Boticário é uma escolha acertada.\nComo se Candidatar Conheça as vagas disponíveis acessando grupoboticario.com.br ou pelo perfil no LinkedIn. O processo seletivo geralmente inclui teste técnico online, entrevista com a liderança técnica e um papo sobre fit cultural. Demonstrar experiência com Kotlin idiomático, arquitetura de microsserviços e plataformas de e-commerce será um diferencial importante.\n","permalink":"https://kotlin.dev.br/empresas/grupo-botic-rio/","summary":"\u003ch2 id=\"grupo-boticário-o-gigante-da-beleza-que-respira-tecnologia-e-kotlin\"\u003eGrupo Boticário: O Gigante da Beleza que Respira Tecnologia e Kotlin\u003c/h2\u003e\n\u003cp\u003eO Grupo Boticário é o maior conglomerado de beleza do Brasil e um dos maiores do mundo. Sediado em Curitiba, no Paraná, o grupo reúne marcas icônicas como O Boticário, Eudora, Quem Disse Berenice?, Vult, Beleza na Web e Australian Gold. Com mais de 47 mil colaboradores e presença em mais de 15 países, a empresa é muito mais do que uma fabricante de cosméticos — é uma potência de tecnologia e inovação que utiliza software de ponta para conectar produtos a consumidores em escala massiva.\u003c/p\u003e","title":"Grupo Boticário — Empresa que Usa Kotlin no Brasil"},{"content":"Grupo Casas Bahia: Kotlin no Coração do Varejo Brasileiro O Grupo Casas Bahia é um dos ícones do varejo brasileiro, reunindo marcas como Casas Bahia, Ponto (antigo Pontofrio) e Extra.com.br em um ecossistema que combina lojas físicas e uma operação digital robusta. Sediado em São Paulo, o grupo emprega mais de 23 mil colaboradores e atende dezenas de milhões de consumidores que buscam desde eletrodomésticos e eletrônicos até móveis e itens para o lar. A trajetória da Casas Bahia se confunde com a própria história do varejo popular no Brasil, e a empresa continua sendo uma referência quando o assunto é democratizar o acesso a bens de consumo.\nNos últimos anos, o Grupo Casas Bahia passou por uma transformação profunda, reposicionando-se como uma empresa de tecnologia aplicada ao varejo. A fusão com a Via Varejo e a posterior reestruturação aceleraram investimentos em plataformas digitais, marketplace, logística last-mile e serviços financeiros. Essa metamorfose colocou a tecnologia no centro da estratégia e abriu espaço para linguagens modernas como Kotlin ganharem protagonismo na stack de desenvolvimento.\nO Grupo no Cenário do Varejo Nacional O varejo brasileiro é um mercado de proporções enormes e concorrência feroz. Empresas como Mercado Livre, Magazine Luiza e Amazon disputam cada clique e cada visita a loja, e o Grupo Casas Bahia responde a essa competição investindo tanto em sua presença física — com centenas de lojas espalhadas pelo país — quanto em sua plataforma digital, que inclui e-commerce próprio e marketplace com milhares de sellers.\nUm diferencial do grupo é sua capilaridade logística. A rede de lojas funciona como mini centros de distribuição para entregas rápidas, um modelo que integra o mundo físico e digital de maneira sofisticada. Gerenciar essa operação exige sistemas de software altamente confiáveis que coordenem estoque, rotas de entrega, disponibilidade de produtos e promessas de prazo em tempo real.\nO marketplace do Grupo Casas Bahia, com milhares de vendedores parceiros, adiciona outra camada de complexidade. Sistemas de onboarding de sellers, cálculo de comissões, gerenciamento de catálogo e resolução de disputas precisam funcionar de forma automática e escalável. É nesse tipo de desafio que engenheiros de software encontram problemas realmente interessantes para resolver.\nComo o Grupo Casas Bahia Utiliza Kotlin Kotlin tem presença crescente na engenharia do Grupo Casas Bahia, especialmente no desenvolvimento de aplicativos Android e nos microsserviços de backend. O app Casas Bahia, um dos mais baixados do varejo brasileiro, é desenvolvido com Kotlin para Android e oferece funcionalidades como navegação de catálogo, busca inteligente de produtos, carrinho de compras, múltiplas formas de pagamento e rastreamento de entregas. Com milhões de usuários ativos, o app precisa ser rápido, estável e intuitivo — e Kotlin contribui diretamente para essa qualidade.\nNo backend, a empresa adota Kotlin com Spring Boot para microsserviços que sustentam operações críticas do e-commerce. O sistema de precificação dinâmica, por exemplo, precisa calcular preços em tempo real considerando promoções, cupons, programas de cashback e regras de marketplace. O motor de busca de produtos também depende de serviços escritos em Kotlin que indexam e ranqueiam milhões de SKUs com base em relevância, disponibilidade e personalização.\nKotlin Coroutines são utilizadas em serviços que orquestram chamadas a múltiplos sistemas durante o checkout. Quando um cliente finaliza uma compra, o sistema precisa verificar estoque, calcular frete, processar pagamento, atualizar o seller e disparar a logística de entrega — tudo isso em poucos segundos. A programação assíncrona eficiente de Kotlin permite que essas operações aconteçam de forma paralela e resiliente.\nA empresa também aplica Kotlin em ferramentas de automação para operações internas. Sistemas que gerenciam a alocação de estoque entre centros de distribuição e lojas, ferramentas de monitoramento de performance de sellers no marketplace e dashboards de acompanhamento de métricas de negócio são alguns exemplos de onde Kotlin é empregado além do consumer-facing.\nStack Tecnológica e Cultura de Engenharia A stack do Grupo Casas Bahia é diversificada e moderna. Kotlin e Java compartilham o espaço do backend JVM, enquanto TypeScript é utilizado para aplicações front-end e Node.js para BFFs (Backend for Frontend). Python é a linguagem preferida para ciência de dados e machine learning. A infraestrutura roda em cloud com AWS como principal provedor, utilizando serviços como ECS, Lambda, DynamoDB, SQS e CloudFront.\nA engenharia do Grupo Casas Bahia se organiza em squads temáticos, cada um responsável por um domínio do negócio — checkout, busca, catálogo, marketplace, logística, pagamentos e assim por diante. Cada squad opera com autonomia e é composto por desenvolvedores, QAs, product managers e designers trabalhando juntos com metodologias ágeis.\nCode reviews são parte da rotina, e a empresa mantém padrões de qualidade com testes automatizados, análise estática de código e pipelines de CI/CD que garantem deploys frequentes e seguros. A observabilidade dos sistemas é levada a sério, com uso de ferramentas como New Relic, Grafana e ELK Stack para monitoramento de performance e detecção de anomalias.\nA cultura valoriza a experimentação controlada. Testes A/B são utilizados extensivamente para validar hipóteses de produto e engenharia, e os times têm liberdade para propor e testar novas abordagens técnicas, desde que suportadas por dados.\nOportunidades de Carreira O Grupo Casas Bahia mantém regularmente mais de 1.400 vagas abertas, muitas delas na área de tecnologia. Desenvolvedores Kotlin encontram oportunidades em times de desenvolvimento Android, engenharia de backend, plataforma de e-commerce e engenharia de dados. Posições de liderança técnica, como tech lead e engineering manager, também são frequentes e oferecem caminho de crescimento para profissionais mais experientes.\nO pacote de benefícios inclui assistência médica e odontológica, vale-refeição e alimentação, seguro de vida, desconto em produtos nas lojas e no e-commerce do grupo — um benefício bastante apreciado pelos colaboradores — e programas de participação nos resultados. O modelo de trabalho varia por posição, mas muitas vagas de tecnologia oferecem flexibilidade de trabalho remoto ou híbrido.\nA empresa investe em desenvolvimento profissional com programas de capacitação, acesso a plataformas de learning e oportunidades de participação em conferências e eventos de tecnologia. Para desenvolvedores no início de carreira, o grupo mantém programas de estágio e trainee com foco em tecnologia e inovação.\nPor Que Desenvolvedores Kotlin Devem Considerar o Grupo Casas Bahia O Grupo Casas Bahia oferece a rara oportunidade de trabalhar em uma empresa que combina tradição no varejo com uma agenda agressiva de transformação digital. Para desenvolvedores Kotlin, isso significa participar de projetos que estão reinventando como milhões de brasileiros compram e recebem produtos. O app que você ajuda a construir será usado por milhões de pessoas. O microsserviço que você otimiza processará milhares de transações por segundo durante a Black Friday.\nA escala do negócio traz desafios técnicos genuínos. Poucas empresas no Brasil precisam lidar com os volumes de tráfego, as complexidades logísticas e a diversidade de integrações que o varejo omnichannel exige. Para quem quer sair da zona de conforto e enfrentar problemas de engenharia de verdade, o Grupo Casas Bahia entrega essa experiência.\nAlém disso, a empresa está em um momento de reconstrução e crescimento da área de tecnologia, o que significa oportunidades para influenciar decisões arquiteturais, propor novas abordagens e ajudar a moldar a cultura de engenharia. Para profissionais Kotlin que querem ter impacto além do código, esse é um momento interessante para entrar.\nComo se Candidatar Acompanhe as vagas disponíveis no LinkedIn do Grupo Casas Bahia. O processo seletivo costuma incluir triagem de currículo, desafio técnico com foco em resolução de problemas, entrevista técnica e conversa com a liderança. Experiência prática com Kotlin, arquitetura de microsserviços e sistemas de alta disponibilidade será bem valorizada.\n","permalink":"https://kotlin.dev.br/empresas/grupo-casas-bahia/","summary":"\u003ch2 id=\"grupo-casas-bahia-kotlin-no-coração-do-varejo-brasileiro\"\u003eGrupo Casas Bahia: Kotlin no Coração do Varejo Brasileiro\u003c/h2\u003e\n\u003cp\u003eO Grupo Casas Bahia é um dos ícones do varejo brasileiro, reunindo marcas como Casas Bahia, Ponto (antigo Pontofrio) e Extra.com.br em um ecossistema que combina lojas físicas e uma operação digital robusta. Sediado em São Paulo, o grupo emprega mais de 23 mil colaboradores e atende dezenas de milhões de consumidores que buscam desde eletrodomésticos e eletrônicos até móveis e itens para o lar. A trajetória da Casas Bahia se confunde com a própria história do varejo popular no Brasil, e a empresa continua sendo uma referência quando o assunto é democratizar o acesso a bens de consumo.\u003c/p\u003e","title":"Grupo Casas Bahia — Empresa que Usa Kotlin no Brasil"},{"content":"iFood: a revolução do delivery brasileiro movida a Kotlin O iFood nasceu em 2011 com uma missão simples e ambiciosa: transformar a maneira como os brasileiros pedem comida. O que começou como uma startup enxuta em Osasco se transformou na maior plataforma de delivery de alimentos da América Latina, conectando milhões de consumidores a centenas de milhares de restaurantes espalhados por todo o Brasil. Com mais de 13 mil colaboradores, o iFood deixou de ser apenas um app de delivery para se tornar um verdadeiro ecossistema de tecnologia alimentar.\nA empresa processa milhões de pedidos por dia, o que exige uma infraestrutura tecnológica robusta, escalável e altamente disponível. Para dar conta desse volume, o iFood fez uma aposta firme em tecnologias modernas — e Kotlin ocupa um papel central nessa estratégia.\nO que o iFood faz e sua posição no mercado O iFood domina o mercado brasileiro de food delivery com folga. A plataforma conecta consumidores, restaurantes e entregadores em um modelo de marketplace que vai muito além do pedido básico. A empresa expandiu suas operações para incluir o iFood Mercado (entregas de supermercado), iFood Benefícios (vale-refeição e vale-alimentação digital), e até serviços financeiros voltados para restaurantes parceiros.\nNo cenário competitivo, o iFood briga com players globais como Rappi e Uber Eats, mas mantém a liderança absoluta no Brasil, com participação de mercado que ultrapassa 80% em diversas cidades. Essa posição dominante não é por acaso: vem de anos de investimento pesado em tecnologia, logística e inteligência artificial.\nComo o iFood usa Kotlin no dia a dia Kotlin é a linguagem principal do aplicativo Android do iFood, que é usado por dezenas de milhões de brasileiros. A migração de Java para Kotlin no app Android começou há alguns anos e hoje a maior parte da base de código mobile já está em Kotlin. A escolha faz todo sentido: Kotlin traz null safety, coroutines para operações assíncronas e uma sintaxe mais enxuta que acelera o desenvolvimento.\nMas o uso de Kotlin no iFood vai muito além do mobile. No backend, a empresa utiliza Kotlin com Spring Boot e Ktor para construir microsserviços que sustentam operações críticas como processamento de pedidos, cálculo de rotas de entrega, precificação dinâmica e sistemas de recomendação. A arquitetura de microsserviços do iFood processa milhões de eventos por segundo usando Kafka, e muitos desses consumidores e produtores são escritos em Kotlin.\nA equipe de engenharia também emprega Kotlin Multiplatform em projetos experimentais, buscando compartilhar lógica de negócio entre as plataformas Android e iOS. Essa abordagem reduz duplicação de código e garante consistência nas regras de negócio.\nStack tecnológica e cultura de engenharia O stack do iFood é um dos mais modernos do Brasil. Além de Kotlin, a empresa trabalha com:\nBackend: Kotlin com Spring Boot, Ktor, Node.js e Go para serviços específicos Mobile: Kotlin nativo para Android, Swift para iOS, e experimentos com Kotlin Multiplatform Infraestrutura: AWS como principal cloud provider, Kubernetes para orquestração de containers, Terraform para infraestrutura como código Dados e ML: Apache Kafka para streaming de eventos, Spark para processamento de dados em larga escala, e modelos de machine learning para recomendação e precificação Observabilidade: Datadog, Grafana e ferramentas internas de monitoramento A cultura de engenharia do iFood é fortemente orientada por dados e experimentação. A empresa mantém uma prática intensa de testes A/B — praticamente qualquer mudança no produto passa por validação experimental antes de chegar a todos os usuários. Squads autônomos trabalham com ownership de ponta a ponta, desde o design da solução até o deploy em produção.\nO iFood também investe pesado em open source e comunidade. A empresa patrocina eventos de tecnologia, publica artigos técnicos no Medium e incentiva seus engenheiros a contribuírem com projetos da comunidade.\nOportunidades de carreira e como é trabalhar no iFood Trabalhar no iFood significa lidar com problemas de escala real. Pouquíssimas empresas no Brasil processam o volume de transações que o iFood processa diariamente, o que cria desafios técnicos genuinamente interessantes: como garantir que o app funcione sem engasgos durante o horário de pico do almoço? Como otimizar rotas de entrega em tempo real para milhares de entregadores simultâneos?\nA empresa oferece modelo de trabalho híbrido, com escritórios em Osasco (sede), São Paulo e Campinas. Os benefícios incluem vale-refeição e alimentação (via iFood Benefícios, claro), plano de saúde, auxílio home office, Gympass e programas de desenvolvimento profissional. O iFood também é conhecido por manter um ambiente descontraído e por valorizar diversidade e inclusão.\nEm termos de crescimento, o iFood tem trilhas de carreira bem definidas tanto para quem quer seguir o caminho técnico (Staff Engineer, Principal Engineer) quanto para quem prefere gestão. Há programas de mentoria interna e um budget anual para cursos e conferências.\nCom quase 3 mil vagas abertas constantemente, o iFood está sempre buscando pessoas talentosas. Para desenvolvedores Kotlin, as oportunidades aparecem em times de Android, backend, plataforma e dados.\nPor que um dev Kotlin deveria considerar o iFood Se você é dev Kotlin e quer trabalhar em uma empresa brasileira que opera em escala massiva, o iFood é uma escolha natural. Você vai usar Kotlin no que a linguagem tem de melhor: apps Android de alta performance, microsserviços backend resilientes e, possivelmente, projetos com Kotlin Multiplatform.\nAlém da escala técnica, o iFood oferece a chance de impactar diretamente a vida de milhões de pessoas — dos consumidores que pedem comida todos os dias aos entregadores que dependem da plataforma como fonte de renda e aos restaurantes que encontram no iFood seu principal canal de vendas digitais.\nA remuneração é competitiva com o mercado de tecnologia brasileiro e o ambiente de trabalho favorece autonomia e inovação. Para quem busca um lugar onde Kotlin não é só uma linguagem secundária mas sim peça fundamental do negócio, o iFood é o lugar certo.\nCandidate-se ao iFood Confira as vagas disponíveis e saiba mais sobre a cultura da empresa no portal de carreiras oficial: https://carreiras.ifood.com.br\n","permalink":"https://kotlin.dev.br/empresas/ifood/","summary":"\u003ch2 id=\"ifood-a-revolução-do-delivery-brasileiro-movida-a-kotlin\"\u003eiFood: a revolução do delivery brasileiro movida a Kotlin\u003c/h2\u003e\n\u003cp\u003eO iFood nasceu em 2011 com uma missão simples e ambiciosa: transformar a maneira como os brasileiros pedem comida. O que começou como uma startup enxuta em Osasco se transformou na maior plataforma de delivery de alimentos da América Latina, conectando milhões de consumidores a centenas de milhares de restaurantes espalhados por todo o Brasil. Com mais de 13 mil colaboradores, o iFood deixou de ser apenas um app de delivery para se tornar um verdadeiro ecossistema de tecnologia alimentar.\u003c/p\u003e","title":"iFood — Empresa que Usa Kotlin no Brasil"},{"content":"Itaú Unibanco: o maior banco privado da América Latina O Itaú Unibanco é o maior banco privado da América Latina e uma das maiores instituições financeiras do mundo. Fundado em 1924 e com sede em São Paulo, o banco emprega cerca de 98 mil pessoas e atende dezenas de milhões de clientes em todo o Brasil. A fusão entre Itaú e Unibanco em 2008 criou uma potência financeira que domina o mercado brasileiro de banking, investimentos, seguros, gestão de patrimônio e serviços corporativos.\nO Itaú é uma empresa que respira tecnologia. A instituição investe bilhões de reais por ano em TI e é reconhecida como um dos maiores empregadores de profissionais de tecnologia no Brasil. O banco entendeu cedo que a digitalização seria o futuro do setor financeiro, e hoje opera uma das maiores e mais sofisticadas operações de tecnologia bancária do mundo.\nO Itaú no cenário financeiro brasileiro O Itaú domina praticamente todos os segmentos do mercado financeiro brasileiro. No banco de varejo, atende milhões de clientes com conta corrente, cartões de crédito, empréstimos, financiamentos e investimentos. No banco de atacado, é parceiro das maiores empresas do país em operações de crédito corporativo, câmbio, mercado de capitais e trade finance. A Itaú Asset Management é uma das maiores gestoras de recursos do Brasil, e a Iti, plataforma digital do grupo, compete diretamente com fintechs e bancos digitais.\nO banco possui uma rede de milhares de agências e caixas eletrônicos, mas o canal digital já responde pela maioria das transações. O aplicativo do Itaú é um dos mais utilizados do Brasil, processando bilhões de transações por ano. A plataforma Iti, voltada para o público mais jovem e digital, opera como um banco digital independente dentro do ecossistema Itaú.\nA operação internacional do banco inclui presença em países da América Latina, Estados Unidos, Europa e Ásia, o que amplia ainda mais a complexidade e a escala dos sistemas tecnológicos.\nComo o Itaú utiliza Kotlin O Itaú é um dos maiores usuários de Kotlin no mercado financeiro brasileiro. A linguagem é empregada de forma estratégica tanto no desenvolvimento mobile quanto no backend.\nNo mobile, Kotlin é a linguagem nativa do aplicativo Itaú para Android, utilizado por dezenas de milhões de clientes. O app é um dos mais completos do mercado financeiro brasileiro: permite realizar transferências via Pix, pagar contas, investir em renda fixa e variável, contratar empréstimos, gerenciar cartões, acessar o programa de pontos e muito mais. A complexidade do app é enorme — são centenas de funcionalidades que precisam funcionar perfeitamente em milhões de dispositivos diferentes. O Kotlin é fundamental para manter essa base de código organizada, segura e performática.\nA plataforma Iti também utiliza Kotlin em seu app Android. Por ser uma operação mais enxuta e ágil que o banco principal, a Iti serve como laboratório para experimentação com tecnologias mais recentes, incluindo Jetpack Compose e Kotlin Multiplatform.\nNo backend, o Itaú adota Kotlin com Spring Boot em uma variedade de microsserviços que processam operações financeiras, análise de crédito, detecção de fraude, motor de ofertas personalizadas e integrações com o Banco Central (Pix, Open Finance, SPB). A migração de sistemas legados escritos em Java e COBOL para microsserviços modernos em Kotlin é um dos maiores projetos de engenharia do banco, envolvendo centenas de engenheiros.\nO Kotlin também é utilizado em ferramentas de automação de testes, pipelines de dados e serviços de integração entre sistemas internos. A expressividade da linguagem e sua compatibilidade com o vasto ecossistema Java do banco fazem dela uma escolha natural para novos projetos.\nStack tecnológica e cultura de engenharia O stack tecnológico do Itaú é um dos mais extensos do Brasil. O banco trabalha com Kotlin, Java, Python, Scala, Go, C#, Swift, React, Angular, bancos de dados Oracle, PostgreSQL, MongoDB, Cassandra, Redis, mensageria com Kafka e IBM MQ, infraestrutura em nuvem (AWS e Azure), além de uma vasta infraestrutura on-premises. Mainframes IBM ainda operam sistemas core de banking, coexistindo com microsserviços modernos em uma arquitetura híbrida.\nA cultura de engenharia do Itaú passou por uma transformação significativa nos últimos anos. O banco investiu em criar uma cultura mais parecida com a de empresas de tecnologia, adotando squads multidisciplinares, práticas ágeis com Scrum e Kanban, DevOps, observabilidade e continuous delivery. O conceito de \u0026ldquo;bank as a platform\u0026rdquo; guia a estratégia de APIs e microsserviços.\nO Itaú possui comunidades técnicas internas vibrantes. Guilds de Kotlin, Java, dados, segurança e outras áreas se reúnem regularmente para compartilhar conhecimento. A empresa promove hackathons, innovation challenges e programas de intraempreendedorismo. O investimento em formação é pesado: o banco mantém a Itaú Educação e uma universidade corporativa que oferece trilhas técnicas especializadas.\nO processo seletivo para engenharia no Itaú é exigente, com etapas que incluem avaliação técnica, pair programming e entrevistas com liderança. A empresa busca profissionais que combinem excelência técnica com capacidade de trabalhar em equipe e entender o impacto de negócio do código que escrevem.\nOportunidades de carreira no Itaú Apesar de o número de vagas listadas publicamente ser relativamente baixo, o Itaú contrata continuamente através de processos seletivos diretos, programas de estágio e trainee, e parcerias com consultorias. A empresa é um dos destinos mais cobiçados para profissionais de tecnologia no Brasil.\nAs posições para desenvolvedores Kotlin incluem engenheiro mobile Android, engenheiro backend, tech lead e arquiteto de software. O Itaú valoriza profissionais com sólida formação em ciência da computação, experiência com sistemas distribuídos, conhecimento em segurança de aplicações e familiaridade com o ecossistema financeiro. A senioridade média dos times é alta, o que cria um ambiente desafiador e de muito aprendizado.\nOs benefícios são de nível premium: PPR expressiva, plano de saúde e odontológico de primeira linha, vale-refeição e alimentação generosos, previdência privada com contribuição do banco, seguro de vida, auxílio creche, Gympass, descontos em produtos financeiros do Itaú e acesso à universidade corporativa. Os salários para engenheiros de software estão entre os mais altos do mercado brasileiro.\nPor que um dev Kotlin deveria considerar o Itaú Trabalhar no Itaú é trabalhar na elite da engenharia de software brasileira. A escala é incomparável — estamos falando do banco que processa uma parcela significativa de todas as transações financeiras do Brasil. Cada linha de código impacta milhões de pessoas e movimenta bilhões de reais.\nOs desafios técnicos são do mais alto nível: alta disponibilidade (99,99%+), latência mínima, segurança rigorosa, conformidade regulatória, e a necessidade de modernizar sistemas legados sem interromper a operação. Para um engenheiro Kotlin que quer trabalhar com problemas realmente difíceis, o Itaú é o campo de batalha ideal.\nA remuneração e os benefícios estão entre os melhores do mercado. E o prestígio de ter o Itaú no currículo abre portas em qualquer lugar do mundo — o banco é reconhecido internacionalmente e seus engenheiros são disputados por fintechs, big techs e outras instituições financeiras.\nSe você busca impacto em escala nacional, remuneração competitiva e a oportunidade de trabalhar com engenheiros excepcionais, o Itaú é uma escolha que fala por si. Acompanhe as oportunidades em itau.com.br e no LinkedIn do Itaú.\n","permalink":"https://kotlin.dev.br/empresas/it/","summary":"\u003ch2 id=\"itaú-unibanco-o-maior-banco-privado-da-américa-latina\"\u003eItaú Unibanco: o maior banco privado da América Latina\u003c/h2\u003e\n\u003cp\u003eO Itaú Unibanco é o maior banco privado da América Latina e uma das maiores instituições financeiras do mundo. Fundado em 1924 e com sede em São Paulo, o banco emprega cerca de 98 mil pessoas e atende dezenas de milhões de clientes em todo o Brasil. A fusão entre Itaú e Unibanco em 2008 criou uma potência financeira que domina o mercado brasileiro de banking, investimentos, seguros, gestão de patrimônio e serviços corporativos.\u003c/p\u003e","title":"IT — Empresa que Usa Kotlin no Brasil"},{"content":"Itaú: Tradição Centenária e Inovação com Kotlin O Itaú é um dos nomes mais reconhecidos do setor financeiro brasileiro, com uma história que remonta a 1924. Sediado em São Paulo, o banco construiu ao longo de um século uma operação que emprega aproximadamente 97 mil pessoas e atende a uma base massiva de clientes em todo o Brasil. De uma agência em Poços de Caldas, Minas Gerais, o Itaú cresceu para se tornar uma instituição financeira de relevância global, com operações em diversos países da América Latina, Europa e Estados Unidos.\nO que diferencia o Itaú no cenário atual é sua capacidade de combinar a solidez de um banco centenário com a velocidade de inovação de uma empresa de tecnologia. A instituição entendeu cedo que o futuro do banking é digital e tem investido de forma massiva em engenharia de software, contratando milhares de profissionais de tecnologia e adotando linguagens modernas como Kotlin para construir a próxima geração de produtos financeiros.\nO Itaú no Mercado Brasileiro O Itaú se destaca no mercado financeiro brasileiro pela amplitude de sua atuação. O banco atende desde o microempreendedor que precisa de uma maquininha de cartão até grandes corporações que movimentam bilhões em operações de tesouraria. Essa diversidade de público exige plataformas tecnológicas capazes de entregar experiências personalizadas para cada segmento, mantendo a segurança e a confiabilidade que o setor financeiro exige.\nO investimento em inovação aberta também é marca registrada do Itaú. Através do Cubo Itaú, o maior hub de empreendedorismo tecnológico da América Latina, o banco fomenta startups e mantém proximidade com o ecossistema de inovação. Essa conexão com o mundo das startups influencia a cultura interna do banco, tornando-o mais aberto a experimentação e a novas tecnologias — incluindo a adoção de Kotlin como linguagem de desenvolvimento.\nA presença digital do Itaú é impressionante. O app do banco está entre os mais utilizados do Brasil, e a empresa investe continuamente para que a experiência digital seja tão boa ou melhor do que a oferecida por qualquer fintech do mercado. Cada interação do cliente com o app — desde consultar o saldo até investir em renda fixa — é alimentada por sistemas complexos que precisam funcionar com perfeição em tempo real.\nKotlin no Desenvolvimento do Itaú O Itaú adota Kotlin como uma de suas linguagens estratégicas para o desenvolvimento de software. No ecossistema mobile, Kotlin é a linguagem principal para o app Android do banco, que serve como o canal primário de relacionamento com milhões de clientes. O app inclui funcionalidades sofisticadas como Pix em tempo real, investimentos com recomendações personalizadas, contratação de crédito, seguros e acesso ao open banking. A robustez que Kotlin oferece é essencial em um contexto onde qualquer falha pode ter impacto financeiro direto.\nNo backend, Kotlin é utilizado para construir microsserviços que formam a espinha dorsal da infraestrutura digital do Itaú. A estratégia de desacoplamento do mainframe, que o banco executa progressivamente, envolve a criação de centenas de microsserviços que encapsulam regras de negócio antes monolíticas. Kotlin, com sua total interoperabilidade com Java, permite que essa migração aconteça de forma suave, aproveitando bibliotecas e frameworks Java existentes enquanto o novo código se beneficia da sintaxe moderna e das funcionalidades avançadas de Kotlin.\nAs Kotlin Coroutines são especialmente valiosas nos serviços do Itaú que precisam lidar com alta concorrência. O processamento de transações Pix, por exemplo, requer respostas em poucos segundos e precisa suportar milhões de operações simultâneas. A programação assíncrona estruturada que Kotlin oferece permite construir esses serviços de forma eficiente sem a complexidade de callbacks aninhados ou a fragilidade de threads tradicionais.\nO banco também utiliza Kotlin em projetos de automação financeira e compliance. Sistemas que verificam transações contra regras regulatórias do Banco Central, que geram relatórios para órgãos fiscalizadores e que monitoram operações em busca de lavagem de dinheiro se beneficiam da expressividade e da segurança de tipos que Kotlin proporciona.\nTecnologias e Cultura de Engenharia O ecossistema tecnológico do Itaú é vasto e sofisticado. Além de Kotlin e Java, o banco utiliza Python para ciência de dados e modelos de risco, TypeScript para interfaces web, Go para serviços de alta performance e C++ para sistemas de trading. A infraestrutura combina data centers proprietários de altíssima disponibilidade com serviços de cloud pública, e a orquestração de microsserviços é feita com Kubernetes em escala massiva.\nA cultura de engenharia do Itaú evoluiu significativamente nos últimos anos, movendo-se de um modelo tradicional de TI para uma organização de produto orientada por squads ágeis. A transformação não foi apenas estrutural — envolveu uma mudança profunda de mentalidade, onde engenheiros de software passaram a ser protagonistas na definição de produtos e na tomada de decisões técnicas.\nO banco promove internamente um programa robusto de desenvolvimento técnico. Existem comunidades de prática dedicadas a Kotlin, JVM, mobile, arquitetura de microsserviços e outras disciplinas. Hackathons semestrais dão aos engenheiros a oportunidade de explorar ideias fora do escopo de seus projetos diários, e muitas dessas ideias acabam sendo incorporadas a produtos reais.\nO compromisso com qualidade de software é visível nas práticas diárias: code reviews obrigatórios, testes automatizados com alta cobertura, monitoramento contínuo com observabilidade avançada e processos de release controlados com feature flags e canary deployments. Para quem vem de ambientes menos estruturados, trabalhar no Itaú é uma oportunidade de aprender práticas de engenharia em escala enterprise.\nCarreira e Benefícios O Itaú oferece uma das experiências de carreira mais completas do mercado de tecnologia brasileiro. As oportunidades para desenvolvedores Kotlin incluem posições em times de desenvolvimento mobile, engenharia de plataforma, backend de serviços financeiros e ferramentas internas. Cargos de liderança técnica, como tech lead e arquiteto, oferecem trilhas de crescimento claras para profissionais seniores.\nO pacote de benefícios reflete o porte do banco: assistência médica e odontológica abrangente, vale-refeição e alimentação, previdência privada complementar, PLR atrativa, seguro de vida, Gympass e descontos em produtos financeiros do Itaú. O modelo de trabalho é híbrido, com escritórios em regiões premium de São Paulo como a Faria Lima e a Vila Olímpia.\nA remuneração no Itaú é competitiva e revisada periodicamente para acompanhar o mercado. O banco participa de pesquisas salariais e se posiciona para atrair talentos que de outra forma iriam para fintechs ou big techs internacionais. A combinação de remuneração atrativa com estabilidade e benefícios de um grande banco é um dos principais chamarizes para profissionais de tecnologia.\nPor Que Desenvolvedores Kotlin Devem Considerar o Itaú O Itaú oferece uma rara convergência de fatores para desenvolvedores Kotlin. Primeiro, a escala: são milhões de usuários, bilhões de transações e sistemas que simplesmente não podem falhar. Trabalhar nesse nível de exigência transforma qualquer engenheiro em um profissional muito mais preparado. Segundo, o propósito: o sistema financeiro é a infraestrutura sobre a qual a economia funciona, e contribuir para torná-lo mais eficiente e acessível tem impacto real na vida das pessoas.\nTerceiro, a oportunidade de participar de uma transformação tecnológica histórica. O Itaú está no meio de uma jornada de modernização que envolve desacoplar décadas de código legado em mainframe e reconstruir a infraestrutura com tecnologias modernas como Kotlin, Kubernetes e event streaming. Para engenheiros que gostam de desafios arquiteturais complexos, essa é a chance de participar de um dos maiores projetos de modernização de software do país.\nPor fim, o Cubo Itaú e o ecossistema de inovação que o banco cultiva oferecem networking e exposição a ideias que vão muito além do que o trabalho cotidiano proporciona. Estar conectado a esse hub de startups enquanto trabalha em um banco centenário é uma experiência profissional singular.\nSaiba Mais e Candidate-se Confira as oportunidades disponíveis no Itaú acessando itau.com.br ou pelo LinkedIn. O processo seletivo inclui etapas de triagem, desafio técnico e entrevistas com o time de engenharia. Familiaridade com Kotlin, arquitetura de microsserviços, práticas de segurança em sistemas financeiros e experiência com sistemas de alta disponibilidade são competências que o banco valoriza bastante na seleção.\n","permalink":"https://kotlin.dev.br/empresas/ita/","summary":"\u003ch2 id=\"itaú-tradição-centenária-e-inovação-com-kotlin\"\u003eItaú: Tradição Centenária e Inovação com Kotlin\u003c/h2\u003e\n\u003cp\u003eO Itaú é um dos nomes mais reconhecidos do setor financeiro brasileiro, com uma história que remonta a 1924. Sediado em São Paulo, o banco construiu ao longo de um século uma operação que emprega aproximadamente 97 mil pessoas e atende a uma base massiva de clientes em todo o Brasil. De uma agência em Poços de Caldas, Minas Gerais, o Itaú cresceu para se tornar uma instituição financeira de relevância global, com operações em diversos países da América Latina, Europa e Estados Unidos.\u003c/p\u003e","title":"Itaú — Empresa que Usa Kotlin no Brasil"},{"content":"Itaú Unibanco: O Maior Banco da América Latina Constrói o Futuro com Kotlin O Itaú Unibanco é a maior instituição financeira da América Latina e um dos maiores bancos privados do mundo. Fundado em 1924 e sediado em São Paulo, o banco é resultado da fusão entre Itaú e Unibanco em 2008, operação que criou um colosso financeiro com mais de 112 mil colaboradores, dezenas de milhões de clientes e presença em mais de 18 países. O Itaú Unibanco oferece um portfólio completo de serviços que inclui conta corrente, investimentos, seguros, crédito, câmbio e soluções corporativas para empresas de todos os portes.\nNos últimos anos, o Itaú Unibanco se reinventou como uma empresa de tecnologia que opera no setor financeiro. Diante da concorrência acirrada de fintechs e bancos digitais, o Itaú investiu bilhões de reais em sua transformação digital, contratando milhares de engenheiros de software e adotando práticas de desenvolvimento ágil em larga escala. Kotlin emergiu como uma das linguagens estratégicas nesse processo, sendo utilizada tanto nos aplicativos mobile quanto nos microsserviços que sustentam a operação bancária.\nPosição no Mercado Financeiro Brasileiro O mercado financeiro brasileiro passa por uma das maiores transformações de sua história. O surgimento de fintechs como Nubank, PicPay e C6 Bank mudou as expectativas dos consumidores, que agora esperam experiências digitais rápidas, intuitivas e sem burocracia. Nesse cenário, o Itaú Unibanco se posiciona como o incumbente que mais rapidamente abraçou a inovação, investindo em tecnologia proprietária e em parcerias estratégicas com startups.\nO super app do Itaú é uma das plataformas bancárias mais completas do Brasil, oferecendo desde operações básicas como transferências e pagamentos de boletos até investimentos, seguros, empréstimos e funcionalidades de open banking. Manter essa plataforma funcionando para dezenas de milhões de usuários com zero tolerância a falhas é um dos maiores desafios de engenharia de software do país.\nAlém do varejo, o Itaú Unibanco atua fortemente nos mercados de investimento (Itaú BBA), gestão de patrimônio (Itaú Private Bank) e seguros. Cada um desses segmentos possui necessidades tecnológicas específicas, desde plataformas de trading de alta frequência até portais de self-service para clientes de alta renda. Com mais de 5.500 vagas de tecnologia anunciadas regularmente, o Itaú é um dos maiores empregadores de desenvolvedores do Brasil.\nKotlin na Engenharia do Itaú Unibanco Kotlin é peça-chave na estratégia de modernização tecnológica do Itaú Unibanco. No desenvolvimento Android, Kotlin é a linguagem padrão para o app do banco, que é utilizado diariamente por dezenas de milhões de brasileiros. O aplicativo precisa oferecer segurança de nível bancário, performance impecável e uma experiência de usuário que rivaliza com as melhores fintechs do mercado. Kotlin contribui para isso com sua null safety — fundamental em um contexto onde erros podem significar prejuízos financeiros —, coroutines para operações assíncronas fluidas e uma sintaxe que permite código mais conciso e manutenível.\nNo backend, o Itaú Unibanco utiliza Kotlin extensivamente na construção de microsserviços que compõem a nova arquitetura do banco. A migração do mainframe legado para uma arquitetura distribuída baseada em cloud é um dos maiores projetos de engenharia de software do Brasil, e Kotlin sobre a JVM é uma das escolhas tecnológicas para os novos serviços. Esses microsserviços processam transações financeiras, gerenciam contas, calculam juros, verificam conformidade regulatória e alimentam dashboards de risco em tempo real.\nA integração com Kafka para event streaming é outra área onde Kotlin se destaca na engenharia do Itaú. Sistemas de detecção de fraude, por exemplo, consomem streams de eventos transacionais e precisam tomar decisões em milissegundos — bloquear uma transação suspeita ou permitir que ela prossiga. Kotlin, com sua eficiência na JVM e suporte a programação reativa, é ideal para esse tipo de aplicação de alta criticidade.\nO Itaú também aplica Kotlin em seus projetos de Kotlin Multiplatform, compartilhando lógica de negócios entre Android e iOS para garantir consistência na experiência do cliente independentemente da plataforma. Essa abordagem reduz duplicação de código e acelera o lançamento de novas features em ambas as plataformas.\nStack Tecnológica e Cultura de Engenharia A stack do Itaú Unibanco é uma das mais diversificadas do mercado brasileiro. Kotlin e Java dominam o ecossistema JVM, enquanto Swift é utilizado para iOS, Python para machine learning e ciência de dados, e TypeScript para aplicações web. A infraestrutura combina data centers próprios com cloud pública (AWS e Azure), e a empresa utiliza massivamente Kubernetes, Kafka, Redis, PostgreSQL e serviços serverless.\nA cultura de engenharia do Itaú se transformou radicalmente nos últimos anos. A empresa adotou um modelo de squads e tribos, com times multidisciplinares que operam de forma ágil. A autonomia dos times é real — cada squad decide como construir suas soluções, quais tecnologias utilizar dentro do catálogo aprovado e como organizar seu fluxo de trabalho. Essa liberdade atraiu para o banco profissionais que antes só considerariam trabalhar em startups ou big techs.\nO Itaú mantém um programa interno de tecnologia chamado iTech, que inclui hackathons, bootcamps, comunidades de prática e eventos de conhecimento. O banco também patrocina conferências e meetups externos, demonstrando comprometimento genuíno com o ecossistema de tecnologia brasileiro. Engenheiros são incentivados a contribuir com open source e a publicar artigos técnicos.\nO rigor em segurança da informação é, compreensivelmente, extremo. Todos os sistemas passam por revisões de segurança, testes de penetração e auditorias regulares. Para engenheiros de software, isso significa desenvolver com uma mentalidade de security-first que se torna uma habilidade valiosa para toda a carreira.\nOportunidades de Carreira e Benefícios Trabalhar no Itaú Unibanco como desenvolvedor Kotlin significa fazer parte de uma das maiores operações de tecnologia do Brasil. As oportunidades vão desde posições de desenvolvedor Android e backend até cargos de arquiteto de soluções, tech lead, staff engineer e engineering manager. O banco também contrata extensivamente para áreas como engenharia de dados, machine learning, segurança da informação e SRE.\nO pacote de benefícios do Itaú é um dos mais robustos do mercado. Assistência médica e odontológica de primeiro nível, vale-refeição e alimentação, previdência privada com contrapartida do banco, PLR significativa, auxílio creche, Gympass e descontos em produtos financeiros do próprio Itaú. O modelo de trabalho é predominantemente híbrido, com modernos escritórios no eixo Faria Lima-Vila Olímpia em São Paulo.\nA remuneração para posições de tecnologia é competitiva e acompanha o mercado. O Itaú entende que compete com fintechs e big techs por talentos e ajusta seus pacotes para se manter atrativo. A estabilidade de um banco centenário combinada com a dinamicidade de uma empresa em plena transformação digital cria um ambiente profissional único.\nPor Que Desenvolvedores Kotlin Devem Considerar o Itaú Unibanco Para desenvolvedores Kotlin que buscam desafios de escala, o Itaú Unibanco é difícil de superar. Estamos falando de sistemas que processam bilhões de reais em transações diárias, atendem dezenas de milhões de usuários simultâneos e precisam funcionar com disponibilidade de 99,99%. Cada microsserviço Kotlin que você constrói precisa ser à prova de falhas, performático e seguro — o tipo de exigência que eleva suas habilidades a outro patamar.\nO impacto do seu trabalho também é tangível. O app que você desenvolve em Kotlin é usado diariamente por uma fatia significativa da população brasileira. Quando você melhora o tempo de resposta de uma API ou implementa uma nova funcionalidade no app, o resultado é percebido por milhões de pessoas.\nA marca Itaú no currículo carrega peso tanto no Brasil quanto internacionalmente. Para quem planeja crescer na carreira — seja permanecendo no banco por muitos anos, seja usando a experiência como trampolim para oportunidades futuras —, o Itaú Unibanco é uma porta de entrada para o primeiro escalão da engenharia de software no país.\nCandidate-se Para explorar as oportunidades de carreira, acesse itau.com.br ou confira as vagas no LinkedIn do Itaú. O processo seletivo geralmente inclui teste técnico online, entrevista técnica com foco em Kotlin e arquitetura de sistemas, e uma etapa comportamental. Preparação em tópicos como microsserviços, event-driven architecture e segurança em sistemas financeiros fará diferença.\n","permalink":"https://kotlin.dev.br/empresas/ita-unibanco/","summary":"\u003ch2 id=\"itaú-unibanco-o-maior-banco-da-américa-latina-constrói-o-futuro-com-kotlin\"\u003eItaú Unibanco: O Maior Banco da América Latina Constrói o Futuro com Kotlin\u003c/h2\u003e\n\u003cp\u003eO Itaú Unibanco é a maior instituição financeira da América Latina e um dos maiores bancos privados do mundo. Fundado em 1924 e sediado em São Paulo, o banco é resultado da fusão entre Itaú e Unibanco em 2008, operação que criou um colosso financeiro com mais de 112 mil colaboradores, dezenas de milhões de clientes e presença em mais de 18 países. O Itaú Unibanco oferece um portfólio completo de serviços que inclui conta corrente, investimentos, seguros, crédito, câmbio e soluções corporativas para empresas de todos os portes.\u003c/p\u003e","title":"Itaú Unibanco — Empresa que Usa Kotlin no Brasil"},{"content":"Sobre Kaê Kaê (pronuncia-se \u0026ldquo;ka-EH\u0026rdquo;) é uma inteligência artificial especializada em Kotlin, criada para ajudar desenvolvedores brasileiros a dominar a linguagem.\nCom conhecimento atualizado sobre Kotlin, Android, Ktor, Compose e todo o ecossistema JetBrains, Kaê escreve tutoriais práticos, guias aprofundados e análises técnicas — sempre em português brasileiro.\nEspecialidades Kotlin para Android — Jetpack Compose, MVVM, Hilt, Room, Navigation Kotlin Backend — Spring Boot, Ktor, microsserviços Kotlin Multiplatform — KMP, Compose Multiplatform Fundamentos — Coroutines, Flow, null safety, extension functions Carreira — Mercado de trabalho, entrevistas, salários no Brasil Transparência Kaê é uma autora assistida por inteligência artificial. Todo o conteúdo é gerado com auxílio de IA e revisado para garantir precisão técnica e relevância para a comunidade brasileira de desenvolvedores Kotlin.\nO nome \u0026ldquo;Kaê\u0026rdquo; é brasileiro e faz referência à letra \u0026ldquo;K\u0026rdquo; de Kotlin.\n","permalink":"https://kotlin.dev.br/autores/kae/","summary":"\u003ch2 id=\"sobre-kaê\"\u003eSobre Kaê\u003c/h2\u003e\n\u003cp\u003eKaê (pronuncia-se \u0026ldquo;ka-EH\u0026rdquo;) é uma inteligência artificial especializada em Kotlin, criada para ajudar desenvolvedores brasileiros a dominar a linguagem.\u003c/p\u003e\n\u003cp\u003eCom conhecimento atualizado sobre \u003cstrong\u003eKotlin, Android, Ktor, Compose e todo o ecossistema JetBrains\u003c/strong\u003e, Kaê escreve tutoriais práticos, guias aprofundados e análises técnicas — sempre em português brasileiro.\u003c/p\u003e\n\u003ch3 id=\"especialidades\"\u003eEspecialidades\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eKotlin para Android\u003c/strong\u003e — Jetpack Compose, MVVM, Hilt, Room, Navigation\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eKotlin Backend\u003c/strong\u003e — Spring Boot, Ktor, microsserviços\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eKotlin Multiplatform\u003c/strong\u003e — KMP, Compose Multiplatform\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eFundamentos\u003c/strong\u003e — Coroutines, Flow, null safety, extension functions\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCarreira\u003c/strong\u003e — Mercado de trabalho, entrevistas, salários no Brasil\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"transparência\"\u003eTransparência\u003c/h3\u003e\n\u003cp\u003eKaê é uma autora assistida por inteligência artificial. Todo o conteúdo é gerado com auxílio de IA e revisado para garantir precisão técnica e relevância para a comunidade brasileira de desenvolvedores Kotlin.\u003c/p\u003e","title":"Kaê — Autora IA do Kotlin Brasil"},{"content":"Localiza\u0026amp;Co: a maior empresa de mobilidade da América Latina A Localiza\u0026amp;Co é referência absoluta quando o assunto é mobilidade no Brasil. Com sede em Belo Horizonte, Minas Gerais, a companhia nasceu como uma locadora de veículos e se transformou em um ecossistema completo de soluções de mobilidade que atende milhões de brasileiros todos os anos. Após a fusão com a Unidas em 2022, a empresa consolidou sua posição como a maior plataforma de mobilidade da América Latina, com uma frota que ultrapassa 600 mil veículos e presença em centenas de cidades brasileiras.\nCom mais de 19.800 colaboradores, a Localiza\u0026amp;Co opera em diversos segmentos: aluguel de carros para pessoas físicas e jurídicas, gestão de frotas corporativas, venda de seminovos e soluções de assinatura de veículos. A empresa está listada na B3 e faz parte do Ibovespa, o que demonstra a relevância que ela tem no mercado de capitais brasileiro. A operação não se limita ao Brasil — a Localiza\u0026amp;Co também atua em outros países da América Latina, ampliando ainda mais o alcance das suas soluções tecnológicas.\nComo a Localiza\u0026amp;Co utiliza Kotlin A transformação digital é um pilar central da estratégia da Localiza\u0026amp;Co. Para uma empresa que gerencia centenas de milhares de veículos e milhões de reservas por ano, a tecnologia precisa ser robusta, escalável e confiável. É nesse contexto que o Kotlin entra como linguagem estratégica.\nNo desenvolvimento mobile, o Kotlin é a linguagem principal para o aplicativo Android da Localiza, utilizado por milhões de clientes para fazer reservas, retirar veículos, gerenciar contratos e acompanhar o status das locações em tempo real. O app precisa lidar com geolocalização, integração com meios de pagamento, notificações push e uma experiência de usuário fluida — tudo isso exige código bem estruturado, e o Kotlin se encaixa perfeitamente nessa demanda.\nNo backend, a empresa vem adotando Kotlin com Spring Boot para construir microsserviços que sustentam a operação digital. Sistemas de precificação dinâmica, gerenciamento de frota, processamento de pagamentos e integrações com parceiros dependem de APIs performáticas e bem documentadas. O Kotlin, com sua interoperabilidade total com o ecossistema Java e recursos modernos como coroutines para programação assíncrona, permite que os times de engenharia entreguem soluções de alta qualidade com maior produtividade.\nA empresa também investe em soluções de dados e inteligência artificial para otimizar a alocação de frota, prever demanda sazonal e personalizar ofertas para os clientes. Pipelines de dados que utilizam tecnologias da JVM se beneficiam diretamente da adoção de Kotlin como linguagem de programação.\nStack tecnológica e cultura de engenharia A Localiza\u0026amp;Co mantém um stack moderno e diversificado. Além de Kotlin e Java, a empresa trabalha com tecnologias como React e React Native no frontend, bancos de dados relacionais e NoSQL, serviços em nuvem (AWS e Azure), mensageria com Kafka, containers Docker e orquestração com Kubernetes. A infraestrutura é pensada para suportar picos de demanda — como feriados prolongados e períodos de férias — sem comprometer a experiência do cliente.\nA cultura de engenharia na Localiza\u0026amp;Co valoriza a autonomia dos times. As squads são organizadas em torno de domínios de negócio, seguindo princípios ágeis com Scrum e Kanban. Cada time tem ownership sobre seus microsserviços, desde o desenvolvimento até a operação em produção, adotando práticas de DevOps e observabilidade com ferramentas como Datadog e Grafana.\nA empresa incentiva fortemente a inovação interna. Hackathons, tech talks e comunidades de prática fazem parte do dia a dia dos times de tecnologia. Existe um investimento claro em capacitação contínua, com acesso a plataformas de aprendizado, participação em conferências e programas de mentoria técnica.\nOportunidades de carreira na Localiza\u0026amp;Co Com quase 1.900 vagas abertas regularmente, a Localiza\u0026amp;Co é uma das empresas que mais contrata profissionais de tecnologia no Brasil. As oportunidades vão desde posições de desenvolvimento mobile e backend até engenharia de dados, arquitetura de software, SRE, QA e gestão técnica.\nPara desenvolvedores Kotlin, as vagas mais comuns envolvem desenvolvimento Android nativo e construção de microsserviços backend. A empresa busca profissionais que tenham experiência com a linguagem ou que venham do ecossistema Java e queiram migrar para Kotlin. Conhecimento em arquitetura limpa, testes automatizados, CI/CD e práticas de code review são diferenciais valorizados.\nA Localiza\u0026amp;Co oferece um pacote de benefícios competitivo que inclui participação nos lucros, plano de saúde e odontológico, vale-alimentação e vale-refeição, auxílio home office, Gympass e, claro, descontos em locação de veículos. O modelo de trabalho é híbrido, com escritório principal em Belo Horizonte, mas também há posições remotas dependendo da área.\nPor que um dev Kotlin deveria considerar a Localiza\u0026amp;Co Trabalhar na Localiza\u0026amp;Co significa atuar em uma empresa que está redefinindo a mobilidade urbana no Brasil. O impacto do seu código é direto: milhões de pessoas usam os sistemas da empresa para se locomover, viajar e trabalhar. Poucas empresas oferecem esse nível de escala combinado com a possibilidade de trabalhar com tecnologias modernas.\nA adoção de Kotlin na empresa está em expansão, o que significa que desenvolvedores que entram agora têm a oportunidade de influenciar decisões técnicas, definir padrões e ajudar a moldar a arquitetura dos sistemas. Além disso, a empresa investe pesado em dados e inteligência artificial, oferecendo aos desenvolvedores a chance de trabalhar na interseção entre engenharia de software e ciência de dados.\nBelo Horizonte, onde fica a sede, é uma das capitais com melhor custo-benefício do Brasil para profissionais de tecnologia. A cidade tem um ecossistema tech vibrante, com diversas comunidades de desenvolvedores, meetups e eventos. E para quem prefere trabalhar de outras cidades, o modelo híbrido e remoto da empresa oferece essa flexibilidade.\nSe você é um desenvolvedor Kotlin buscando desafios em escala, uma empresa sólida financeiramente e um ambiente que valoriza inovação tecnológica, a Localiza\u0026amp;Co merece estar no topo da sua lista. Acompanhe as vagas abertas pelo LinkedIn da Localiza\u0026amp;Co e dê o próximo passo na sua carreira.\n","permalink":"https://kotlin.dev.br/empresas/localiza-co/","summary":"\u003ch2 id=\"localizaco-a-maior-empresa-de-mobilidade-da-américa-latina\"\u003eLocaliza\u0026amp;Co: a maior empresa de mobilidade da América Latina\u003c/h2\u003e\n\u003cp\u003eA Localiza\u0026amp;Co é referência absoluta quando o assunto é mobilidade no Brasil. Com sede em Belo Horizonte, Minas Gerais, a companhia nasceu como uma locadora de veículos e se transformou em um ecossistema completo de soluções de mobilidade que atende milhões de brasileiros todos os anos. Após a fusão com a Unidas em 2022, a empresa consolidou sua posição como a maior plataforma de mobilidade da América Latina, com uma frota que ultrapassa 600 mil veículos e presença em centenas de cidades brasileiras.\u003c/p\u003e","title":"Localiza\u0026Co — Empresa que Usa Kotlin no Brasil"},{"content":"Magazine Luiza: o gigante do varejo brasileiro que respira tecnologia O Magazine Luiza — carinhosamente conhecido como Magalu — é muito mais do que uma rede de lojas. Fundada em 1957 em Franca, no interior de São Paulo, a empresa se reinventou nas últimas décadas e se posicionou como uma das maiores plataformas digitais de varejo do Brasil. Com mais de 42 mil colaboradores, o Magalu opera um ecossistema que combina mais de 1.300 lojas físicas espalhadas pelo país com uma operação digital robusta que inclui marketplace, logística própria, fintech e superapp.\nA transformação digital do Magalu é um caso de estudo reconhecido internacionalmente. A empresa passou de varejista tradicional para uma plataforma tecnológica que conecta milhões de consumidores a milhares de sellers. O Luizalabs, braço de tecnologia e inovação da companhia, é o motor por trás dessa revolução — e Kotlin tem um papel cada vez mais importante nessa engrenagem.\nA presença do Magalu no mercado brasileiro O Magalu é uma das marcas mais reconhecidas do Brasil. Além do e-commerce e das lojas físicas, a empresa opera o MagaluPay (solução de pagamentos), o Magalu Entregas (logística integrada), o marketplace que reúne dezenas de milhares de lojistas parceiros, e plataformas como Netshoes, Zattini e Época Cosméticos, que foram adquiridas ao longo dos anos.\nA empresa é listada na B3 e possui uma base de clientes que ultrapassa 50 milhões de pessoas. Em datas como Black Friday e Natal, a infraestrutura tecnológica do Magalu precisa suportar picos massivos de tráfego — estamos falando de milhões de acessos simultâneos, centenas de milhares de pedidos por hora e uma cadeia logística que precisa funcionar como um relógio.\nComo o Magazine Luiza usa Kotlin O Luizalabs é onde a mágica acontece. Com centenas de engenheiros de software, o laboratório de tecnologia do Magalu desenvolve e mantém os sistemas que sustentam toda a operação digital da empresa. Kotlin é uma das linguagens centrais nesse ecossistema.\nNo desenvolvimento Android, o Kotlin é a linguagem padrão para o superapp do Magalu, um dos aplicativos de e-commerce mais baixados do Brasil. O app oferece funcionalidades que vão desde a busca e compra de produtos até o rastreamento de entregas, cashback, pagamentos via MagaluPay e integração com serviços de marketplace. A complexidade do app exige uma base de código bem organizada, e o Kotlin proporciona isso com seus recursos de null safety, extension functions e data classes.\nNo backend, o Magalu utiliza Kotlin em microsserviços que lidam com catálogo de produtos, motor de busca, recomendações personalizadas, gestão de pedidos e integrações com sellers do marketplace. A empresa opera uma arquitetura de microsserviços distribuída em larga escala, onde a confiabilidade e a performance são requisitos não negociáveis. Kotlin, combinado com frameworks como Spring Boot e Ktor, permite que os times construam serviços enxutos e eficientes.\nA empresa também investe em event-driven architecture, utilizando Apache Kafka para processamento de eventos em tempo real. Microsserviços escritos em Kotlin consomem e produzem eventos que alimentam desde sistemas de notificação até modelos de machine learning para recomendação de produtos.\nStack tecnológica e a cultura do Luizalabs O stack do Luizalabs é extenso e moderno. Além de Kotlin e Java, os times trabalham com Python, Go, Node.js, React, Flutter, bancos de dados como PostgreSQL, MongoDB e Elasticsearch, infraestrutura em nuvem com Google Cloud Platform e AWS, containers Docker, Kubernetes, e pipelines de CI/CD com GitHub Actions e Jenkins.\nA cultura de engenharia do Luizalabs é bastante reconhecida no mercado brasileiro de tecnologia. Os times são organizados em squads multidisciplinares com autonomia para tomar decisões técnicas. A empresa pratica inner source — código compartilhado internamente entre times — e incentiva contribuições open source. O Luizalabs já publicou diversas bibliotecas e ferramentas de código aberto.\nO ambiente valoriza experimentação e aprendizado contínuo. Tech talks semanais, capítulos técnicos, hackathons trimestrais e acesso a conferências como KotlinConf, QCon e TDC fazem parte da rotina. O processo de code review é rigoroso, e a empresa tem uma cultura forte de testes automatizados e observabilidade.\nOportunidades de carreira no Magalu Com mais de 2.600 vagas abertas regularmente, o Magalu é um dos maiores empregadores de tecnologia do Brasil. As oportunidades incluem desenvolvimento Android e iOS, backend engineering, engenharia de dados, machine learning, infraestrutura, segurança e liderança técnica.\nPara devs Kotlin, as posições mais frequentes são de engenheiro Android sênior e engenheiro backend. A empresa valoriza profissionais com experiência em arquitetura de software, que saibam trabalhar em sistemas de alta escala e que tenham vivência com práticas de engenharia como TDD, pair programming e continuous delivery.\nOs benefícios incluem salários competitivos, PLR, plano de saúde e odontológico, vale-refeição e alimentação, auxílio home office, descontos em compras nas lojas do grupo e programas de desenvolvimento profissional. O modelo de trabalho é predominantemente híbrido, com hubs em São Paulo e outras capitais.\nPor que um dev Kotlin deveria considerar o Magazine Luiza Trabalhar no Magalu é ter a chance de impactar a vida de milhões de brasileiros. Poucos lugares no país oferecem a combinação de escala massiva, desafios técnicos reais e uma cultura de engenharia madura. Quando seu código entra em produção no Magalu, ele é exercitado por milhões de usuários no mesmo dia.\nO Luizalabs é reconhecido como um dos melhores lugares para se trabalhar com tecnologia no Brasil. A empresa aparece consistentemente em rankings de melhores empregadores do setor, e a comunidade de ex-Luizalabs é forte no mercado — um sinal claro de que a experiência adquirida lá é valorizada.\nSe você quer trabalhar com Kotlin em escala, em uma empresa genuinamente brasileira que compete de igual para igual com gigantes globais, o Magalu é o lugar certo. Confira as vagas disponíveis em magazineluiza.com.br e no LinkedIn do Magazine Luiza.\n","permalink":"https://kotlin.dev.br/empresas/magazine-luiza/","summary":"\u003ch2 id=\"magazine-luiza-o-gigante-do-varejo-brasileiro-que-respira-tecnologia\"\u003eMagazine Luiza: o gigante do varejo brasileiro que respira tecnologia\u003c/h2\u003e\n\u003cp\u003eO Magazine Luiza — carinhosamente conhecido como Magalu — é muito mais do que uma rede de lojas. Fundada em 1957 em Franca, no interior de São Paulo, a empresa se reinventou nas últimas décadas e se posicionou como uma das maiores plataformas digitais de varejo do Brasil. Com mais de 42 mil colaboradores, o Magalu opera um ecossistema que combina mais de 1.300 lojas físicas espalhadas pelo país com uma operação digital robusta que inclui marketplace, logística própria, fintech e superapp.\u003c/p\u003e","title":"Magazine Luiza — Empresa que Usa Kotlin no Brasil"},{"content":"Mercado Livre: o gigante do e-commerce latino-americano que confia em Kotlin O Mercado Livre é a maior plataforma de e-commerce e fintech da América Latina. Presente em 18 países, a operação brasileira é de longe a mais relevante, responsável pela maior fatia da receita e do volume de transações do grupo. Com quase 40 mil funcionários globalmente e uma infraestrutura que sustenta centenas de milhões de listagens ativas, o Mercado Livre é um caso de estudo em engenharia de escala — e Kotlin faz parte dessa história.\nFundada na Argentina em 1999, a empresa rapidamente se enraizou no Brasil e hoje tem seu principal centro de tecnologia em São Paulo. A empresa é listada na Nasdaq (MELI) e seu valor de mercado a coloca entre as maiores empresas de tecnologia das Américas.\nAtuação no Brasil e posição de mercado O Mercado Livre Brasil opera um ecossistema que vai muito além da compra e venda online. A plataforma engloba:\nMercado Livre Marketplace: o maior marketplace da América Latina, com centenas de milhões de ofertas ativas Mercado Pago: fintech que processa pagamentos dentro e fora da plataforma, oferece conta digital, cartão de crédito, empréstimos e investimentos Mercado Envios: braço logístico próprio com centros de distribuição (fulfillment centers) espalhados pelo Brasil, frota aérea dedicada e entrega no mesmo dia em diversas regiões Mercado Ads: plataforma de publicidade para vendedores Mercado Shops: criação de lojas virtuais independentes integradas ao ecossistema No e-commerce brasileiro, o Mercado Livre lidera com vantagem significativa sobre Amazon Brasil, Shopee e Magazine Luiza. No setor de pagamentos, o Mercado Pago compete de igual para igual com Nubank, PicPay e PagBank.\nO papel do Kotlin na engenharia do Mercado Livre Com a escala de operação do Mercado Livre, cada decisão tecnológica tem consequências enormes. Kotlin foi adotado de forma estratégica em múltiplas frentes da engenharia.\nNo desenvolvimento Android, Kotlin é a linguagem padrão do aplicativo do Mercado Livre e do Mercado Pago. Esses apps estão instalados em dezenas de milhões de dispositivos Android no Brasil e precisam funcionar de forma fluida em aparelhos de todas as faixas de preço — do flagship ao entry-level. As coroutines do Kotlin são amplamente utilizadas para gerenciar chamadas de rede, carregamento de imagens de produtos e sincronização de carrinho de compras de forma assíncrona sem travar a interface do usuário.\nNo backend, o Mercado Livre historicamente construiu sua plataforma sobre Java e Go. A adoção de Kotlin no backend tem crescido de forma consistente, aproveitando a interoperabilidade perfeita com o ecossistema Java existente. Microsserviços novos em times que já trabalham com a JVM frequentemente escolhem Kotlin como linguagem principal, utilizando frameworks como Spring Boot e gRPC para comunicação entre serviços.\nA engenharia do Mercado Livre também explora Kotlin em ferramentas internas de produtividade, automação de testes e pipelines de CI/CD. A expressividade da linguagem torna DSLs (Domain Specific Languages) internas mais legíveis e fáceis de manter.\nStack tecnológica e cultura de engenharia A infraestrutura do Mercado Livre é uma das mais impressionantes da América Latina:\nBackend: Java, Kotlin, Go e Node.js como linguagens principais, com microsserviços se comunicando via gRPC e mensageria assíncrona Mobile: Kotlin para Android, Swift para iOS, com investimento em arquiteturas modulares para permitir que dezenas de squads contribuam no mesmo app sem conflitos Infraestrutura: cloud privada própria combinada com serviços de nuvem pública, Kubernetes em larga escala, Fury (plataforma interna de deploy) Dados: Big Data com processamento distribuído, modelos de machine learning para recomendação de produtos, detecção de fraudes e precificação dinâmica Frontend: React para a web, com server-side rendering para SEO das páginas de produto A cultura de engenharia é profundamente orientada por métricas e experimentação. O Mercado Livre roda milhares de testes A/B simultaneamente e cada feature é monitorada por indicadores de negócio claros. A empresa adota fortemente a filosofia de \u0026ldquo;you build it, you run it\u0026rdquo; — o squad que desenvolve um serviço é responsável por operá-lo em produção.\nO Mercado Livre também é conhecido pelo programa \u0026ldquo;MELI Developer\u0026rdquo;, que incentiva contribuições internas de ferramentas e bibliotecas reutilizáveis. Engenheiros têm autonomia para propor melhorias arquiteturais e liderar iniciativas técnicas cross-team.\nCarreira e dia a dia no Mercado Livre Trabalhar no Mercado Livre é trabalhar em escala latino-americana. Os desafios técnicos incluem lidar com picos de tráfego brutais (datas como Black Friday geram volumes de requisições comparáveis às maiores plataformas do mundo), garantir experiência de compra consistente em dispositivos com conexões instáveis e manter a integridade financeira de milhões de transações diárias pelo Mercado Pago.\nA empresa mantém escritórios em São Paulo (principal hub de tecnologia no Brasil), além de centros em Buenos Aires, Montevidéu e outras cidades. O modelo de trabalho é predominantemente híbrido, com flexibilidade que varia por equipe.\nO pacote de benefícios é robusto: salário competitivo, participação nos lucros, stock units (RSUs) da empresa listada na Nasdaq, plano de saúde premium, vale-refeição, Gympass, licença parental estendida e budget para educação continuada. O Mercado Livre frequentemente aparece em rankings de melhores empresas para trabalhar na América Latina.\nAs trilhas de carreira são bem estruturadas, tanto para o caminho técnico quanto para gestão. Engenheiros podem progredir até posições de Distinguished Engineer, com impacto técnico em toda a organização.\nPor que um dev Kotlin deveria considerar o Mercado Livre O Mercado Livre oferece a oportunidade de trabalhar com Kotlin em uma das maiores plataformas de tecnologia da América Latina. A escala de operação é genuinamente rara: estamos falando de uma empresa que processa bilhões de dólares em transações por ano e entrega milhões de pacotes por mês com logística própria.\nPara um desenvolvedor Kotlin, o Mercado Livre apresenta desafios técnicos que vão desde a otimização de performance em apps Android para dispositivos de entrada até microsserviços backend que precisam sustentar picos de tráfego inimagináveis. A base de código é madura, os padrões de engenharia são elevados e o investimento em ferramentas internas é significativo.\nSe você busca impacto em escala continental, remuneração competitiva com equity de uma empresa de capital aberto e a chance de trabalhar com Kotlin em problemas que realmente importam, o Mercado Livre merece estar no topo da sua lista.\nVeja as vagas abertas Confira as oportunidades no site oficial: https://mercadolivre.com\n","permalink":"https://kotlin.dev.br/empresas/mercado-livre-brasil/","summary":"\u003ch2 id=\"mercado-livre-o-gigante-do-e-commerce-latino-americano-que-confia-em-kotlin\"\u003eMercado Livre: o gigante do e-commerce latino-americano que confia em Kotlin\u003c/h2\u003e\n\u003cp\u003eO Mercado Livre é a maior plataforma de e-commerce e fintech da América Latina. Presente em 18 países, a operação brasileira é de longe a mais relevante, responsável pela maior fatia da receita e do volume de transações do grupo. Com quase 40 mil funcionários globalmente e uma infraestrutura que sustenta centenas de milhões de listagens ativas, o Mercado Livre é um caso de estudo em engenharia de escala — e Kotlin faz parte dessa história.\u003c/p\u003e","title":"Mercado Livre Brasil — Empresa que Usa Kotlin no Brasil"},{"content":"Natura: gigante brasileira de cosméticos usa Kotlin para reinventar a beleza A Natura é a maior empresa de cosméticos do Brasil e uma das maiores do mundo. Fundada em 1969 em São Paulo, a empresa construiu sua marca sobre pilares de sustentabilidade, inovação e valorização da biodiversidade brasileira. Com o grupo Natura \u0026amp;Co — que inclui as marcas Natura, Avon, The Body Shop e Aesop — a empresa emprega mais de 47 mil pessoas e atende milhões de consumidores em dezenas de países. Por trás dos produtos que chegam ao banheiro de cada brasileiro, existe uma operação tecnológica sofisticada onde Kotlin desempenha um papel cada vez mais importante.\nA Natura não é uma empresa de tecnologia no sentido tradicional, mas é uma empresa que entendeu cedo que tecnologia é o caminho para escalar seu modelo de negócio único. O modelo de venda direta — com milhões de consultoras e consultores espalhados pelo Brasil — depende fundamentalmente de plataformas digitais para funcionar.\nPresença no Brasil e posição de mercado A Natura lidera o mercado brasileiro de cosméticos, perfumaria e higiene pessoal, competindo com multinacionais como Unilever, L\u0026rsquo;Oréal e P\u0026amp;G. Sua vantagem competitiva vem de uma combinação de fatores: ingredientes extraídos de forma sustentável da biodiversidade amazônica, uma rede de venda direta com milhões de consultoras e uma marca profundamente enraizada na cultura brasileira.\nA operação da Natura no Brasil é imensa e multifacetada:\nVenda direta: mais de um milhão de consultoras Natura no Brasil utilizam ferramentas digitais para gerenciar seus negócios, fazer pedidos, compartilhar catálogos e interagir com clientes E-commerce: vendas online diretas ao consumidor pelo site e app da Natura, além de presença em marketplaces Lojas físicas: rede de lojas próprias e franqueadas em shoppings e ruas de todo o país Avon: integração da operação Avon no Brasil, trazendo mais uma rede massiva de revendedoras para o ecossistema digital Sustentabilidade: a Natura é referência global em ESG, sendo empresa B certificada e mantendo programas de preservação na Amazônia Como a Natura usa Kotlin A digitalização da rede de consultoras é o coração da estratégia tecnológica da Natura — e Kotlin é uma das linguagens que viabilizam essa transformação.\nNo desenvolvimento mobile, Kotlin é utilizado nos aplicativos Android voltados para as consultoras Natura e Avon. Esses apps são ferramentas de trabalho essenciais: é por eles que as consultoras montam seus pedidos, acompanham suas vendas, consultam catálogos de produtos, gerenciam seus clientes e acessam treinamentos. O app precisa funcionar bem em smartphones de todas as faixas de preço — lembrando que muitas consultoras utilizam aparelhos de entrada — e lidar com conectividade variável em todas as regiões do Brasil.\nAs coroutines do Kotlin são especialmente úteis nesse contexto, permitindo que operações como sincronização de catálogos, upload de pedidos e carregamento de imagens de produtos aconteçam em segundo plano sem travar a interface. A null safety de Kotlin também reduz significativamente os crashes em produção, o que é crucial quando o app é a ferramenta de trabalho principal de milhões de pessoas.\nNo backend, a Natura emprega Kotlin com Spring Boot para construir APIs e microsserviços que sustentam a plataforma de vendas digitais. Processamento de pedidos, cálculo de comissões para consultoras, gestão de estoque, integração com sistemas logísticos e personalização de ofertas são exemplos de domínios onde microsserviços Kotlin operam. A empresa também utiliza Kotlin em sistemas de integração entre as diferentes marcas do grupo, unificando catálogos, dados de clientes e fluxos operacionais.\nOutro uso interessante é em ferramentas de realidade aumentada e experiência digital. A Natura investiu em tecnologia de \u0026ldquo;virtual try-on\u0026rdquo; que permite que consumidoras testem maquiagem virtualmente pelo celular. Os componentes backend que sustentam essas experiências — como processamento de imagem e servir modelos de renderização — se beneficiam da performance e expressividade de Kotlin.\nStack tecnológica e cultura de engenharia O ecossistema tecnológico da Natura vem se modernizando aceleradamente:\nBackend: Kotlin e Java com Spring Boot, Node.js para BFFs, Python para ciência de dados Mobile: Kotlin para Android, Swift para iOS, com experimentação em soluções cross-platform para agilizar desenvolvimento E-commerce: plataforma de commerce composable, com arquitetura headless e APIs que alimentam múltiplos canais de venda Cloud: AWS como principal provedor de nuvem, Kubernetes para orquestração, arquitetura de microsserviços Dados e IA: modelos de recomendação de produtos, segmentação de consultoras, previsão de demanda, análise de sentimento em redes sociais Experiências digitais: realidade aumentada para virtual try-on, personalização de experiência baseada em perfil de pele e preferências A cultura de engenharia da Natura é fortemente influenciada pelos valores da empresa. Sustentabilidade e impacto social não são apenas discurso corporativo — permeiam as decisões técnicas, desde a otimização de infraestrutura cloud para reduzir a pegada de carbono até o design de apps acessíveis para consultoras com diferentes níveis de letramento digital.\nA empresa organiza seus times de tecnologia em squads ágeis com autonomia para tomar decisões técnicas. Há uma comunidade de prática interna ativa, com tech talks, coding dojos e hackathons focados em resolver problemas reais do negócio. A Natura também mantém parcerias com universidades e centros de pesquisa para projetos de inovação em biotecnologia e tecnologia da informação.\nOportunidades de carreira A Natura mantém seu principal centro de tecnologia em São Paulo, no bairro do Itaim Bibi, além de um campus em Cajamar (sede industrial e administrativa). Com mais de 1.500 vagas tipicamente abertas na empresa, incluindo posições de tecnologia, a Natura está sempre buscando talentos.\nPara desenvolvedores Kotlin, as oportunidades aparecem nos times de apps para consultoras (Android), plataforma de e-commerce (backend), sistemas de integração entre marcas, experiências digitais e dados. Cada uma dessas áreas traz desafios distintos e a chance de impactar uma operação de escala continental.\nO pacote de benefícios reflete os valores da empresa: plano de saúde e odontológico, vale-refeição e alimentação, participação nos resultados, previdência privada, Gympass, licença parental estendida (6 meses para mães e 40 dias para pais), desconto generoso em produtos Natura e Avon, e um dia de folga no aniversário. A Natura também foi pioneira em oferecer benefícios inclusivos para famílias diversas.\nO modelo de trabalho é híbrido, com flexibilidade que varia por equipe. A empresa investe em treinamento e desenvolvimento com acesso a plataformas de aprendizado, budget para conferências e programas de mentoria. A trilha de carreira técnica permite crescimento sem necessidade de migrar para gestão.\nPor que um dev Kotlin deveria considerar a Natura A Natura oferece a rara combinação de uma empresa com propósito genuíno e desafios tecnológicos relevantes. Se você é dev Kotlin e quer que seu trabalho tenha impacto social além do técnico, a Natura é uma escolha natural.\nOs desafios de engenharia são reais: construir apps que funcionem para milhões de consultoras em todo o Brasil, muitas delas em regiões com infraestrutura digital precária; processar volumes massivos de pedidos durante campanhas promocionais; integrar sistemas de marcas que operam em dezenas de países; e criar experiências digitais inovadoras como virtual try-on de maquiagem.\nTrabalhar na Natura também significa fazer parte de uma empresa que é referência mundial em sustentabilidade e responsabilidade social. Para muitos profissionais de tecnologia que buscam alinhamento entre carreira e valores pessoais, isso faz toda a diferença. E se você curte Kotlin, vai encontrar espaço para aplicar a linguagem em contextos variados e desafiadores.\nConfira as oportunidades Visite o site oficial da Natura e explore as vagas: https://natura.com.br\n","permalink":"https://kotlin.dev.br/empresas/natura/","summary":"\u003ch2 id=\"natura-gigante-brasileira-de-cosméticos-usa-kotlin-para-reinventar-a-beleza\"\u003eNatura: gigante brasileira de cosméticos usa Kotlin para reinventar a beleza\u003c/h2\u003e\n\u003cp\u003eA Natura é a maior empresa de cosméticos do Brasil e uma das maiores do mundo. Fundada em 1969 em São Paulo, a empresa construiu sua marca sobre pilares de sustentabilidade, inovação e valorização da biodiversidade brasileira. Com o grupo Natura \u0026amp;Co — que inclui as marcas Natura, Avon, The Body Shop e Aesop — a empresa emprega mais de 47 mil pessoas e atende milhões de consumidores em dezenas de países. Por trás dos produtos que chegam ao banheiro de cada brasileiro, existe uma operação tecnológica sofisticada onde Kotlin desempenha um papel cada vez mais importante.\u003c/p\u003e","title":"Natura — Empresa que Usa Kotlin no Brasil"},{"content":"Porto: o novo capítulo de uma das maiores seguradoras do Brasil A Porto é o resultado da evolução de marca de uma das empresas mais sólidas do mercado brasileiro. Com sede em São Paulo e fundada em 1945, a companhia passou por um rebranding estratégico que reflete sua expansão para além do seguro tradicional. Hoje, a Porto opera sob três verticais de negócio — Porto Seguro (seguros), Porto Bank (serviços financeiros) e Porto Saúde (planos de saúde) — atendendo milhões de clientes em todo o território nacional.\nCom quase 24 mil colaboradores, a Porto é uma empresa que combina a solidez de quem está no mercado há décadas com a agilidade de quem entende que o futuro é digital. A companhia é listada na B3 e mantém resultados financeiros consistentes, o que garante investimentos contínuos em tecnologia e inovação.\nA Porto no mercado brasileiro A Porto é líder no segmento de seguros de automóvel no Brasil e possui posições relevantes em seguros residenciais, empresariais, de vida e saúde. O Porto Bank oferece cartões de crédito, consórcios, financiamentos e conta digital. Já o Porto Saúde é um dos planos de saúde que mais crescem no país.\nO que diferencia a Porto de muitas empresas do setor é sua capacidade de oferecer uma experiência integrada ao cliente. Um segurado que tem seu carro na Porto pode também ter seu plano de saúde, seu cartão de crédito e seu consórcio — tudo gerenciado em uma única plataforma digital. Essa visão de ecossistema exige uma infraestrutura tecnológica sofisticada, e é aí que o time de tecnologia da Porto entra em cena.\nComo a Porto utiliza Kotlin A Porto tem uma operação de tecnologia de grande porte, e Kotlin é uma das linguagens que sustentam essa operação. A utilização acontece tanto no desenvolvimento mobile quanto no backend.\nO aplicativo Android da Porto é o principal canal digital da empresa. Por ele, os clientes gerenciam apólices de seguro, acionam assistência, consultam extratos do cartão Porto Bank, agendam consultas pelo Porto Saúde e acompanham seus consórcios. A diversidade de funcionalidades exige uma arquitetura mobile bem pensada, e o Kotlin é a base para isso. O time de Android utiliza padrões como MVVM, Clean Architecture e Jetpack Compose para garantir que o app seja rápido, estável e fácil de manter.\nNo backend, a Porto adota Kotlin com Spring Boot em microsserviços que processam cotações de seguros, análise de sinistros, transações financeiras do Porto Bank e integrações com parceiros e reguladores. A natureza crítica dessas operações — estamos falando de dinheiro e proteção patrimonial das pessoas — exige um nível elevado de confiabilidade. O Kotlin contribui com sua segurança de tipos, suporte nativo a coroutines para operações assíncronas e compatibilidade total com bibliotecas Java consolidadas.\nA empresa também explora Kotlin Multiplatform em iniciativas internas para compartilhar lógica de negócio entre as plataformas Android e iOS, reduzindo duplicação de código e acelerando o tempo de entrega de novas funcionalidades.\nStack tecnológica e cultura de engenharia O ecossistema tecnológico da Porto é amplo. A empresa trabalha com Kotlin, Java, Python, .NET, TypeScript, React, Angular, Swift, bancos de dados como PostgreSQL, SQL Server, MongoDB e Redis, mensageria com Kafka e RabbitMQ, e infraestrutura em nuvem com AWS e Azure.\nA arquitetura está em constante evolução. A Porto investe na migração de sistemas legados para uma arquitetura moderna baseada em microsserviços, containers e orquestração com Kubernetes. Práticas de DevOps, pipelines de CI/CD, infraestrutura como código com Terraform e observabilidade com Datadog e New Relic são parte do dia a dia dos times.\nA cultura de engenharia da Porto privilegia ownership e colaboração. Os times são multidisciplinares e organizados em torno de produtos e domínios de negócio. Cada squad tem autonomia para escolher ferramentas e abordagens técnicas dentro de guidelines corporativos. A empresa promove comunidades de prática, tech talks regulares e programas de mentoria que conectam engenheiros juniores a profissionais mais experientes.\nUm diferencial da Porto é o investimento em dados e inteligência artificial. A empresa utiliza modelos preditivos para precificação de seguros, detecção de fraudes, análise de comportamento de clientes e personalização de ofertas. Engenheiros que trabalham com Kotlin frequentemente interagem com pipelines de dados e APIs de modelos de machine learning.\nOportunidades de carreira na Porto Com mais de 3.200 vagas abertas regularmente, a Porto é uma das empresas que mais contrata profissionais de tecnologia no Brasil. As oportunidades abrangem desenvolvimento mobile (Android e iOS), backend, frontend, engenharia de dados, ciência de dados, arquitetura de software, SRE, segurança da informação e liderança técnica.\nPara desenvolvedores Kotlin, as posições mais comuns são engenheiro Android e engenheiro backend. A empresa busca profissionais com experiência em sistemas distribuídos, arquitetura de microsserviços, testes automatizados e práticas ágeis. Conhecimento em Jetpack Compose, Kotlin Coroutines e Spring Boot são habilidades frequentemente mencionadas nas descrições de vagas.\nOs benefícios são robustos: PLR, plano de saúde Porto Saúde, plano odontológico, vale-refeição e alimentação, previdência privada, seguro de vida, cartão Porto Bank com condições especiais, auxílio creche, Gympass e programas de desenvolvimento profissional. O modelo de trabalho é híbrido, com escritórios em São Paulo.\nPor que um dev Kotlin deveria considerar a Porto A Porto oferece uma combinação rara: a estabilidade de uma empresa quase octogenária com os desafios técnicos de uma fintech. O ecossistema de produtos — seguros, banco, saúde — cria uma complexidade de domínio que mantém o trabalho intelectualmente estimulante.\nO volume de vagas abertas demonstra que a empresa está em modo de crescimento tecnológico. Para um desenvolvedor Kotlin, isso significa que há espaço para evolução de carreira, tanto na trilha técnica quanto na de gestão. A Porto valoriza profissionais que crescem internamente e oferece programas estruturados de desenvolvimento de liderança.\nA localização em São Paulo coloca o profissional no maior ecossistema de tecnologia do Brasil, com acesso a comunidades, eventos e networking. E para quem valoriza o propósito no trabalho, a Porto atua em um setor que protege pessoas em momentos difíceis — uma missão que dá significado ao código que você escreve. Veja as vagas disponíveis em porto.vc e no LinkedIn da Porto.\n","permalink":"https://kotlin.dev.br/empresas/porto/","summary":"\u003ch2 id=\"porto-o-novo-capítulo-de-uma-das-maiores-seguradoras-do-brasil\"\u003ePorto: o novo capítulo de uma das maiores seguradoras do Brasil\u003c/h2\u003e\n\u003cp\u003eA Porto é o resultado da evolução de marca de uma das empresas mais sólidas do mercado brasileiro. Com sede em São Paulo e fundada em 1945, a companhia passou por um rebranding estratégico que reflete sua expansão para além do seguro tradicional. Hoje, a Porto opera sob três verticais de negócio — Porto Seguro (seguros), Porto Bank (serviços financeiros) e Porto Saúde (planos de saúde) — atendendo milhões de clientes em todo o território nacional.\u003c/p\u003e","title":"Porto — Empresa que Usa Kotlin no Brasil"},{"content":"Porto Seguro: tradição e inovação no mercado de seguros brasileiro A Porto Seguro é uma das seguradoras mais tradicionais e respeitadas do Brasil. Fundada em 1945, a empresa construiu ao longo de quase oito décadas uma reputação sólida no mercado de seguros, sendo reconhecida pela qualidade do atendimento ao cliente e pela diversidade de produtos que oferece. Com aproximadamente 16 mil colaboradores, a Porto Seguro é hoje muito mais do que uma seguradora — é um conglomerado de serviços que abrange seguros de automóvel, residência, vida e saúde, além de consórcios, serviços financeiros e até proteção patrimonial.\nA marca Porto Seguro é sinônimo de confiança para milhões de brasileiros. A empresa atende mais de 10 milhões de clientes e possui uma rede de assistência 24 horas que é referência no mercado. Com o avanço da digitalização, a Porto Seguro vem investindo pesadamente em tecnologia para modernizar seus processos, melhorar a experiência do segurado e criar novos produtos digitais.\nO mercado de seguros e a transformação digital O setor de seguros no Brasil passa por uma transformação profunda. Consumidores esperam contratar, gerenciar e acionar seus seguros pelo celular, com poucos cliques e sem burocracia. A regulamentação do Open Insurance pelo Banco Central e pela Susep acelerou ainda mais a necessidade de APIs abertas e sistemas interoperáveis.\nA Porto Seguro entendeu cedo que tecnologia seria o diferencial competitivo do futuro. A empresa criou uma área de tecnologia robusta que desenvolve desde aplicativos mobile para segurados até plataformas internas para corretores, sistemas de precificação baseados em dados e soluções de telemática para monitoramento de veículos.\nComo a Porto Seguro utiliza Kotlin Kotlin tem um papel crescente na estratégia tecnológica da Porto Seguro. A linguagem é utilizada em duas frentes principais: desenvolvimento de aplicativos Android e construção de microsserviços backend.\nNo mobile, o aplicativo Android da Porto Seguro permite que os segurados consultem apólices, acionem assistência 24 horas, acompanhem sinistros, façam pagamentos e acessem a rede de prestadores de serviço. A experiência precisa ser impecável — quando alguém está no meio de uma emergência, o app não pode falhar. O Kotlin, com sua tipagem segura e tratamento explícito de nulidade, ajuda a construir um aplicativo mais estável e confiável.\nNo backend, a Porto Seguro utiliza Kotlin com Spring Boot para desenvolver microsserviços que sustentam operações críticas. Sistemas de cotação e precificação de seguros, análise de risco, processamento de sinistros e integrações com o ecossistema Open Insurance são construídos com foco em performance e segurança. O Kotlin facilita a escrita de código conciso e legível, o que é especialmente valioso em domínios complexos como o atuarial e o regulatório.\nA empresa também aplica Kotlin em projetos de automação e integração. Bots de atendimento, workflows automatizados de sinistro e ferramentas internas de produtividade se beneficiam da expressividade da linguagem e da maturidade do ecossistema JVM.\nStack tecnológica e cultura de engenharia A Porto Seguro mantém um stack diversificado que reflete a complexidade do seu negócio. Além de Kotlin e Java, a empresa trabalha com .NET em sistemas legados, Python para ciência de dados e modelos atuariais, React no frontend web, bancos de dados Oracle, PostgreSQL e MongoDB, e infraestrutura em nuvem com AWS e Azure.\nA arquitetura da empresa está em processo de modernização contínua. Sistemas monolíticos estão sendo decompostos em microsserviços, e a adoção de containers com Docker e Kubernetes é cada vez mais ampla. Mensageria com RabbitMQ e Kafka, API Gateway, service mesh e observabilidade com ferramentas como Splunk e Dynatrace fazem parte do arsenal tecnológico.\nA cultura de engenharia da Porto Seguro valoriza estabilidade e qualidade. Dado que os sistemas lidam com dados sensíveis de segurados e transações financeiras, a empresa tem um forte foco em segurança da informação, testes automatizados e processos de deploy controlados. Ao mesmo tempo, existe espaço para inovação — a empresa promove hackatons internos e incentiva que os times proponham melhorias tecnológicas.\nOportunidades de carreira na Porto Seguro A Porto Seguro mantém cerca de 200 vagas de tecnologia abertas regularmente. As posições abrangem desenvolvimento mobile, backend, frontend, engenharia de dados, arquitetura de software, segurança da informação e gestão de projetos técnicos.\nPara desenvolvedores Kotlin, as oportunidades são principalmente em desenvolvimento Android e engenharia de microsserviços. A empresa valoriza profissionais com experiência no ecossistema JVM, conhecimento em arquitetura de microsserviços, familiaridade com práticas de CI/CD e testes automatizados. Experiência no setor financeiro ou de seguros é um diferencial, mas não um requisito — a Porto Seguro investe em treinamento para que novos colaboradores aprendam o domínio de negócio.\nOs benefícios incluem PLR, plano de saúde e odontológico, vale-refeição e alimentação, previdência privada, seguro de vida (naturalmente), descontos em produtos do grupo e programas de bem-estar. O modelo de trabalho é híbrido, com escritórios em São Paulo.\nPor que um dev Kotlin deveria considerar a Porto Seguro Trabalhar na Porto Seguro é atuar em uma empresa que protege o patrimônio e a tranquilidade de milhões de famílias brasileiras. O setor de seguros oferece desafios técnicos únicos: modelagem de risco, precificação dinâmica, processamento de grandes volumes de dados e integração com um ecossistema regulatório em constante evolução.\nA estabilidade financeira da empresa é um atrativo importante. A Porto Seguro é uma empresa lucrativa, com décadas de história, que oferece segurança de carreira sem abrir mão da inovação tecnológica. Para quem busca um ambiente onde é possível crescer profissionalmente com previsibilidade e bons benefícios, a Porto Seguro é uma escolha sólida.\nAlém disso, o setor de insurtech está em franca expansão no Brasil. Profissionais que adquirem experiência nesse domínio se tornam muito valorizados no mercado. Acompanhe as vagas em portoseguro.com.br e no LinkedIn da Porto Seguro.\n","permalink":"https://kotlin.dev.br/empresas/porto-seguro/","summary":"\u003ch2 id=\"porto-seguro-tradição-e-inovação-no-mercado-de-seguros-brasileiro\"\u003ePorto Seguro: tradição e inovação no mercado de seguros brasileiro\u003c/h2\u003e\n\u003cp\u003eA Porto Seguro é uma das seguradoras mais tradicionais e respeitadas do Brasil. Fundada em 1945, a empresa construiu ao longo de quase oito décadas uma reputação sólida no mercado de seguros, sendo reconhecida pela qualidade do atendimento ao cliente e pela diversidade de produtos que oferece. Com aproximadamente 16 mil colaboradores, a Porto Seguro é hoje muito mais do que uma seguradora — é um conglomerado de serviços que abrange seguros de automóvel, residência, vida e saúde, além de consórcios, serviços financeiros e até proteção patrimonial.\u003c/p\u003e","title":"Porto Seguro — Empresa que Usa Kotlin no Brasil"},{"content":"Sicredi: o cooperativismo financeiro que move o Brasil O Sicredi é uma das instituições financeiras mais singulares do Brasil. Fundado em 1902 no Rio Grande do Sul, é a primeira cooperativa de crédito da América Latina e hoje constitui um sistema cooperativo formado por mais de 2 mil agências espalhadas por todos os estados brasileiros. Com mais de 32 mil colaboradores e cerca de 8 milhões de associados, o Sicredi prova que é possível fazer serviços financeiros de um jeito diferente — colocando as pessoas no centro e distribuindo os resultados de forma justa entre os cooperados.\nDiferente dos bancos tradicionais, no Sicredi cada associado é dono do negócio e participa das decisões. Esse modelo cooperativista não é apenas um discurso: ele influencia diretamente a cultura da empresa, incluindo a área de tecnologia. Os times de engenharia desenvolvem soluções que impactam a vida de milhões de pessoas em comunidades de todo o Brasil, desde grandes capitais até municípios do interior que muitas vezes não são atendidos por outros bancos.\nA posição do Sicredi no mercado financeiro O Sicredi oferece um portfólio completo de produtos financeiros: conta corrente, poupança, cartões de crédito e débito, empréstimos e financiamentos, seguros, consórcios, investimentos e previdência. A instituição é a quinta maior em crédito no agronegócio brasileiro e possui uma carteira de crédito que ultrapassa R$ 200 bilhões.\nO crescimento do Sicredi nos últimos anos tem sido expressivo. Enquanto grandes bancos fecham agências, o Sicredi abre novas unidades — especialmente em regiões onde a presença física faz diferença para o associado. Ao mesmo tempo, a instituição investe forte em canais digitais para atender a demanda de quem prefere resolver tudo pelo celular ou computador.\nComo o Sicredi utiliza Kotlin A transformação digital do Sicredi é um dos projetos mais ambiciosos do setor financeiro cooperativo brasileiro, e o Kotlin é uma peça fundamental nessa jornada.\nNo desenvolvimento mobile, o Kotlin é a linguagem principal do aplicativo Android do Sicredi. O app permite que os associados realizem transferências via Pix, paguem boletos, consultem extratos, invistam, contratem seguros e até participem das assembleias da cooperativa. A experiência mobile precisa ser tão boa quanto a de qualquer banco digital, e o time de Android do Sicredi utiliza Kotlin com Jetpack Compose, Coroutines e Navigation Component para entregar uma interface moderna e responsiva.\nNo backend, o Sicredi adota Kotlin com Spring Boot para a construção de microsserviços que processam transações financeiras, gerenciam contas, operam o motor de crédito e integram com o Sistema de Pagamentos Brasileiro (SPB), o Pix e o Open Finance. A criticidade desses sistemas é máxima: uma falha pode significar que um agricultor não consegue receber o pagamento da sua safra ou que uma família não consegue pagar suas contas. O Kotlin ajuda a construir sistemas mais seguros e legíveis, com menos bugs em produção.\nA instituição também utiliza Kotlin em ferramentas internas e automações. Processos de onboarding digital de novos associados, análise de crédito automatizada e geração de relatórios regulatórios se beneficiam da produtividade que a linguagem oferece.\nStack tecnológica e cultura de engenharia O Sicredi opera um stack tecnológico robusto e em constante modernização. Além de Kotlin e Java, a instituição trabalha com Python, Node.js, React, Angular, Swift, bancos de dados Oracle, PostgreSQL e MongoDB, mensageria com Apache Kafka, infraestrutura em nuvem com AWS e containers orquestrados com Kubernetes.\nA arquitetura do Sicredi está em transição de sistemas legados mainframe para uma arquitetura moderna de microsserviços. Esse processo de modernização é um dos grandes desafios técnicos da empresa e oferece aos engenheiros a oportunidade de participar de decisões arquiteturais de grande impacto. A migração envolve strangler fig patterns, event sourcing e design cuidadoso de APIs.\nA cultura de engenharia do Sicredi reflete os valores cooperativistas da instituição. A colaboração entre times é genuína — não é apenas um valor no papel. Os squads são multidisciplinares e trabalham com metodologias ágeis. A empresa incentiva o compartilhamento de conhecimento através de guilds técnicos, tech talks, dojos de programação e participação em comunidades externas.\nO Sicredi possui um centro de tecnologia em Porto Alegre, mas também tem hubs em São Paulo e permite trabalho remoto para diversas posições. A empresa investe significativamente em capacitação, com programas de formação interna, acesso a plataformas de aprendizado online, certificações e patrocínio para participação em conferências.\nOportunidades de carreira no Sicredi Com mais de 4.400 vagas abertas regularmente, o Sicredi é um dos maiores empregadores de tecnologia do sul do Brasil e está expandindo sua presença em outras regiões. As oportunidades abrangem desenvolvimento mobile, backend, frontend, engenharia de dados, data science, arquitetura de software, DevOps, SRE, segurança da informação, agilidade e gestão técnica.\nPara desenvolvedores Kotlin, as vagas mais frequentes são de engenheiro Android e engenheiro backend. O Sicredi busca profissionais com experiência em desenvolvimento de sistemas distribuídos, APIs RESTful, testes automatizados e familiaridade com o ecossistema financeiro. Experiência com Pix, Open Finance ou regulamentação do Banco Central é um diferencial, mas a empresa oferece treinamento para quem vem de outros setores.\nO pacote de benefícios é um dos mais completos do mercado: PPR (participação nos resultados), plano de saúde Unimed, plano odontológico, vale-refeição e alimentação, auxílio creche, Gympass, previdência privada com contrapartida da empresa, seguro de vida e descontos em produtos financeiros do Sicredi. O modelo de trabalho é híbrido ou remoto, dependendo da posição.\nPor que um dev Kotlin deveria considerar o Sicredi O Sicredi oferece algo que poucos empregadores conseguem: propósito genuíno combinado com desafios técnicos de alta complexidade. Trabalhar em uma instituição financeira cooperativa significa que o impacto do seu código vai direto para comunidades reais — o agricultor do interior do Paraná, o pequeno empreendedor do Mato Grosso, a família que conseguiu financiar sua primeira casa.\nA escala da operação é significativa: 8 milhões de associados, bilhões de reais em transações e integração com todo o sistema financeiro nacional. Não faltam problemas complexos para resolver. E o momento é especialmente interessante: a migração de sistemas legados para uma arquitetura moderna cria oportunidades para engenheiros que querem influenciar decisões técnicas de longo prazo.\nPorto Alegre, onde fica o principal hub de tecnologia, oferece excelente qualidade de vida e um custo de vida menor que São Paulo. A cidade tem uma comunidade de tecnologia ativa e diversas universidades formando talentos na área. E para quem prefere trabalhar de outro lugar, muitas vagas aceitam trabalho remoto.\nSe você é um desenvolvedor Kotlin que valoriza propósito, estabilidade e a chance de trabalhar em sistemas financeiros de escala nacional, o Sicredi merece sua atenção. Explore as oportunidades em sicredi.com.br e no LinkedIn do Sicredi.\n","permalink":"https://kotlin.dev.br/empresas/sicredi/","summary":"\u003ch2 id=\"sicredi-o-cooperativismo-financeiro-que-move-o-brasil\"\u003eSicredi: o cooperativismo financeiro que move o Brasil\u003c/h2\u003e\n\u003cp\u003eO Sicredi é uma das instituições financeiras mais singulares do Brasil. Fundado em 1902 no Rio Grande do Sul, é a primeira cooperativa de crédito da América Latina e hoje constitui um sistema cooperativo formado por mais de 2 mil agências espalhadas por todos os estados brasileiros. Com mais de 32 mil colaboradores e cerca de 8 milhões de associados, o Sicredi prova que é possível fazer serviços financeiros de um jeito diferente — colocando as pessoas no centro e distribuindo os resultados de forma justa entre os cooperados.\u003c/p\u003e","title":"Sicredi — Empresa que Usa Kotlin no Brasil"},{"content":"Stefanini Group: a multinacional brasileira de TI com presença global O Stefanini Group é uma das maiores empresas de tecnologia nascidas no Brasil. Com sede em Jaguariúna, no interior de São Paulo, a companhia se consolidou como uma multinacional de serviços de TI e consultoria que atua em mais de 40 países. Com aproximadamente 24 mil colaboradores ao redor do mundo, a Stefanini atende clientes de diversos setores — desde bancos e seguradoras até indústrias, varejo, governo e telecomunicações — oferecendo soluções que vão de desenvolvimento de software a transformação digital, automação, inteligência artificial e gestão de infraestrutura.\nA história da Stefanini é um caso emblemático de empreendedorismo brasileiro no setor de tecnologia. A empresa cresceu de forma orgânica e por meio de aquisições estratégicas, incorporando empresas especializadas em áreas como analytics, cibersegurança, experiência do usuário e soluções em nuvem. Essa diversificação permitiu que o grupo ofereça um portfólio completo de serviços tecnológicos, competindo de frente com gigantes globais como Accenture, Capgemini e TCS.\nA atuação da Stefanini no mercado brasileiro No Brasil, a Stefanini é um dos nomes mais reconhecidos em serviços de TI. A empresa atende grandes corporações brasileiras e multinacionais com operação no país, oferecendo desde outsourcing de equipes de desenvolvimento até projetos completos de transformação digital. A presença em Jaguariúna, uma cidade conhecida pelo polo tecnológico no interior paulista, dá à empresa acesso a um pool de talentos qualificado e a um ecossistema de inovação que inclui universidades como a Unicamp.\nA Stefanini também possui escritórios em São Paulo, Belo Horizonte, Curitiba, Rio de Janeiro e outras capitais, além de operações em cidades menores. Essa distribuição geográfica permite que a empresa atenda clientes em todo o Brasil e ofereça oportunidades de trabalho em diversas regiões.\nUm dos diferenciais da Stefanini é sua capacidade de operar como parceiro estratégico de longo prazo para seus clientes. Em vez de apenas fornecer mão de obra, a empresa se posiciona como co-criadora de soluções, participando desde a concepção até a sustentação de sistemas complexos.\nComo a Stefanini utiliza Kotlin Por atuar em consultoria e serviços de TI, a Stefanini trabalha com uma variedade enorme de tecnologias, e Kotlin tem conquistado espaço crescente nos projetos da empresa.\nNo desenvolvimento mobile, a Stefanini utiliza Kotlin para construir aplicativos Android para seus clientes. Bancos que precisam de apps para correntistas, varejistas que querem um canal mobile para vendas, seguradoras que necessitam de um portal digital para segurados — muitos desses projetos são desenvolvidos pelas equipes da Stefanini utilizando Kotlin como linguagem principal. A empresa mantém times especializados em desenvolvimento Android nativo, com profissionais que dominam Jetpack Compose, arquiteturas MVVM e MVI, e integração com APIs REST e GraphQL.\nNo backend, Kotlin é adotado em projetos que rodam na JVM, especialmente em microsserviços construídos com Spring Boot. Clientes do setor financeiro, por exemplo, demandam sistemas de alta disponibilidade e performance para processamento de transações, e a Stefanini entrega essas soluções utilizando Kotlin pela sua segurança de tipos e pela produtividade que a linguagem oferece em relação ao Java tradicional.\nA Stefanini também utiliza Kotlin em projetos de automação e integração. Bots corporativos, pipelines de processamento de dados e ferramentas de integração entre sistemas legados e plataformas modernas frequentemente se beneficiam da expressividade e concisão do Kotlin.\nStack tecnológica e cultura de engenharia O stack da Stefanini é um dos mais diversificados do mercado, reflexo da natureza do negócio de consultoria. Além de Kotlin e Java, os times trabalham com .NET, Python, JavaScript/TypeScript, React, Angular, Vue.js, Flutter, Swift, bancos de dados de todos os tipos (Oracle, SQL Server, PostgreSQL, MongoDB, DynamoDB), nuvens AWS, Azure e Google Cloud, e ferramentas de DevOps como Jenkins, GitLab CI, Docker e Kubernetes.\nA empresa possui centros de excelência em áreas como inteligência artificial, automação robótica de processos (RPA), analytics, cibersegurança e cloud. Esses centros funcionam como polos de conhecimento que apoiam os projetos em andamento e desenvolvem soluções proprietárias que aceleram a entrega para os clientes.\nA cultura de engenharia na Stefanini varia conforme o projeto e o cliente, mas existe um esforço corporativo para padronizar boas práticas. A empresa promove certificações técnicas (AWS, Azure, Scrum, ITIL), trilhas de carreira estruturadas e programas de capacitação contínua. Para profissionais que gostam de aprender coisas novas constantemente, a natureza rotativa dos projetos de consultoria é um atrativo.\nA Stefanini investe em programas de formação de talentos, incluindo academias internas para desenvolvedores em início de carreira. Esses programas são uma porta de entrada para quem está começando e quer aprender Kotlin em um ambiente profissional.\nOportunidades de carreira na Stefanini Com mais de 2 mil vagas abertas regularmente, a Stefanini oferece oportunidades em praticamente todas as áreas de tecnologia. As posições incluem desenvolvimento mobile, backend, frontend, full-stack, DevOps, QA, arquitetura de software, gestão de projetos, análise de dados, inteligência artificial e segurança da informação.\nPara desenvolvedores Kotlin, as oportunidades são variadas. Há vagas para atuação em projetos de clientes (alocação), em squads internas que desenvolvem produtos próprios da Stefanini, e em times de centro de excelência. A empresa busca profissionais com diferentes níveis de experiência, desde juniores até especialistas e arquitetos.\nOs benefícios incluem plano de saúde e odontológico, vale-refeição e alimentação, seguro de vida, auxílio educação, descontos em universidades parceiras, Gympass e programas de certificação. O modelo de trabalho varia conforme o projeto — há posições presenciais, híbridas e remotas, distribuídas por diversas cidades do Brasil.\nPor que um dev Kotlin deveria considerar a Stefanini A Stefanini é uma excelente opção para desenvolvedores Kotlin que valorizam diversidade de projetos e aprendizado constante. Em uma consultoria, você não fica preso a um único produto ou domínio — ao longo da carreira, pode trabalhar em projetos para bancos, indústrias, varejo e governo, cada um com seus desafios e tecnologias específicas.\nA dimensão global da empresa também é um diferencial. Profissionais da Stefanini têm a possibilidade de trabalhar em projetos internacionais, interagir com equipes de outros países e até realizar transferências para escritórios no exterior. Para quem sonha em internacionalizar a carreira sem sair de uma empresa brasileira, essa é uma oportunidade real.\nOutro ponto forte é a estabilidade. Por ter uma base de clientes diversificada e contratos de longo prazo, a Stefanini oferece uma previsibilidade de emprego que startups e empresas menores muitas vezes não conseguem garantir. Confira as oportunidades em stefanini.com e no LinkedIn da Stefanini.\n","permalink":"https://kotlin.dev.br/empresas/stefanini-group/","summary":"\u003ch2 id=\"stefanini-group-a-multinacional-brasileira-de-ti-com-presença-global\"\u003eStefanini Group: a multinacional brasileira de TI com presença global\u003c/h2\u003e\n\u003cp\u003eO Stefanini Group é uma das maiores empresas de tecnologia nascidas no Brasil. Com sede em Jaguariúna, no interior de São Paulo, a companhia se consolidou como uma multinacional de serviços de TI e consultoria que atua em mais de 40 países. Com aproximadamente 24 mil colaboradores ao redor do mundo, a Stefanini atende clientes de diversos setores — desde bancos e seguradoras até indústrias, varejo, governo e telecomunicações — oferecendo soluções que vão de desenvolvimento de software a transformação digital, automação, inteligência artificial e gestão de infraestrutura.\u003c/p\u003e","title":"Stefanini Group — Empresa que Usa Kotlin no Brasil"},{"content":"Stone: fintech brasileira que aposta em Kotlin para transformar o mercado financeiro A Stone é uma das fintechs mais importantes do Brasil. Listada na Nasdaq sob o ticker STNE, a empresa se consolidou como referência em soluções de pagamento para comerciantes brasileiros, atendendo desde o microempreendedor individual até grandes redes varejistas. Com mais de 13 mil funcionários espalhados pelo país, a Stone construiu sua reputação pela proximidade com o cliente e por uma obsessão com tecnologia de ponta.\nO que diferencia a Stone de outros adquirentes tradicionais é a mentalidade de empresa de tecnologia. Enquanto bancos tradicionais tratam meios de pagamento como commodity, a Stone trata cada maquininha, cada transação e cada integração como um problema de engenharia que merece a melhor solução possível. É nesse contexto que Kotlin entra como peça-chave.\nO que a Stone faz e onde ela se posiciona no mercado A Stone atua como adquirente e oferece um ecossistema completo de soluções financeiras para o lojista brasileiro. O portfólio da empresa inclui maquininhas de cartão (os famosos terminais POS), soluções de pagamento online via gateway, conta digital para empresas, crédito para capital de giro e software de gestão (através da Linx, adquirida em 2021).\nA aquisição da Linx, líder em software de gestão para varejo no Brasil, foi um marco estratégico. Com essa junção, a Stone passou a oferecer uma solução integrada que vai desde o ERP do lojista até o processamento do pagamento no caixa. Isso gera um volume absurdo de dados e transações que precisam fluir em tempo real com altíssima confiabilidade.\nNo mercado de adquirência, a Stone disputa espaço com Cielo, Rede, PagSeguro e outros players. Sua diferenciação está no atendimento humanizado (os famosos \u0026ldquo;Agentes Stone\u0026rdquo; espalhados pelo Brasil) e na qualidade técnica dos seus produtos.\nComo a Stone usa Kotlin Kotlin permeia diversas frentes de engenharia na Stone. No mundo mobile, o aplicativo Android da Stone — utilizado tanto por lojistas para acompanhar vendas quanto internamente pelos agentes comerciais — é desenvolvido predominantemente em Kotlin. A migração do legado Java para Kotlin foi uma prioridade, aproveitando a interoperabilidade nativa entre as duas linguagens para fazer a transição de forma incremental e segura.\nNos terminais POS baseados em Android (como o Stone Smart), Kotlin também está presente. Desenvolver software para maquininhas inteligentes é um nicho fascinante: o código precisa ser eficiente em dispositivos com recursos limitados, lidar com conectividade intermitente e processar transações financeiras com segurança criptográfica rigorosa. Kotlin, com suas coroutines e null safety, se encaixa perfeitamente nesse cenário.\nNo backend, a Stone utiliza Kotlin com frameworks como Spring Boot para construir microsserviços que processam transações financeiras, calculam taxas, gerenciam antifraude e alimentam dashboards analíticos em tempo real. O processamento de pagamentos exige latência baixíssima e tolerância zero a falhas, o que torna a segurança de tipos do Kotlin especialmente valiosa.\nStack tecnológica e cultura de engenharia O ecossistema técnico da Stone é vasto e diverso:\nBackend: Kotlin e Java com Spring Boot, além de serviços em Go e Elixir para componentes de alta concorrência Mobile: Kotlin para Android (apps e terminais POS), Swift para iOS Infraestrutura: AWS e infraestrutura própria em data centers (exigência regulatória do setor financeiro), Kubernetes, Docker Dados: Apache Kafka para event streaming, pipelines de dados com Spark, data lakes para análise de comportamento transacional Segurança: HSMs (Hardware Security Modules) para criptografia de transações, PCI DSS compliance em toda a stack A cultura de engenharia da Stone é marcada pela mentalidade de ownership. Times são organizados em squads que possuem autonomia para tomar decisões técnicas, desde a escolha de bibliotecas até a arquitetura dos serviços que mantêm. A empresa promove hackathons internos e tem um programa robusto de tech talks onde engenheiros compartilham aprendizados.\nOutro aspecto importante é a cultura de resiliência. Quando se lida com dinheiro, qualquer minuto de indisponibilidade significa prejuízo real para o lojista. Por isso, a Stone investe pesado em chaos engineering, testes de carga e práticas de SRE para garantir que seus sistemas aguentem picos de Black Friday e outras datas críticas do varejo.\nOportunidades de carreira e dia a dia na Stone A Stone mantém escritórios em São Paulo (sede), Rio de Janeiro e diversos hubs regionais pelo Brasil. O modelo de trabalho varia por equipe, com opções presenciais e híbridas. Com mais de 3.300 vagas tipicamente abertas, a empresa está em constante expansão.\nPara desenvolvedores Kotlin, as oportunidades são variadas. Você pode trabalhar no time de aplicativos Android para lojistas, no desenvolvimento de software para terminais POS, em microsserviços backend de processamento de pagamentos ou nos times de dados e analytics. Cada uma dessas áreas apresenta desafios técnicos únicos.\nOs benefícios incluem remuneração competitiva com o mercado fintech, participação nos resultados, plano de saúde e odontológico, vale-refeição e alimentação, Gympass e auxílio educação. A Stone também oferece stock options para funcionários, o que é um diferencial relevante para uma empresa listada na bolsa americana.\nA empresa valoriza formação contínua e mantém parcerias com universidades e plataformas de aprendizado. Engenheiros têm acesso a budget para conferências, cursos e certificações. A trilha de carreira técnica é bem definida, permitindo que desenvolvedores cresçam até posições de Staff e Principal Engineer sem precisar migrar para gestão.\nPor que um dev Kotlin deveria olhar para a Stone A Stone oferece algo raro no mercado brasileiro: a chance de trabalhar com Kotlin em contextos variados dentro da mesma empresa. Poucos lugares permitem que você desenvolva desde apps Android de consumo até software embarcado em terminais de pagamento, passando por microsserviços backend de alta criticidade — tudo usando Kotlin.\nO setor financeiro traz desafios técnicos que vão além do convencional. Segurança, compliance, disponibilidade e performance são requisitos inegociáveis. Trabalhar na Stone vai fazer de você um engenheiro mais completo, porque o custo de um bug em produção não é apenas uma tela de erro — é dinheiro real de comerciantes reais.\nSe você quer aplicar Kotlin em problemas de verdade, com impacto direto na economia brasileira e na vida de milhões de lojistas, a Stone é uma aposta segura.\nExplore as vagas na Stone Acesse o site oficial e confira as oportunidades disponíveis: https://stone.com.br\n","permalink":"https://kotlin.dev.br/empresas/stone/","summary":"\u003ch2 id=\"stone-fintech-brasileira-que-aposta-em-kotlin-para-transformar-o-mercado-financeiro\"\u003eStone: fintech brasileira que aposta em Kotlin para transformar o mercado financeiro\u003c/h2\u003e\n\u003cp\u003eA Stone é uma das fintechs mais importantes do Brasil. Listada na Nasdaq sob o ticker STNE, a empresa se consolidou como referência em soluções de pagamento para comerciantes brasileiros, atendendo desde o microempreendedor individual até grandes redes varejistas. Com mais de 13 mil funcionários espalhados pelo país, a Stone construiu sua reputação pela proximidade com o cliente e por uma obsessão com tecnologia de ponta.\u003c/p\u003e","title":"Stone — Empresa que Usa Kotlin no Brasil"},{"content":"TOTVS: a maior empresa de software do Brasil adota Kotlin para modernizar o mercado A TOTVS é a maior empresa de tecnologia do Brasil e a líder absoluta em software de gestão empresarial na América Latina. Fundada em 1983 em São Paulo, a empresa acumula mais de quatro décadas de experiência atendendo empresas de todos os portes e segmentos — do pequeno comércio de bairro à grande indústria. Com mais de 16 mil colaboradores e mais de 5 mil vagas tipicamente abertas, a TOTVS está em constante crescimento e busca desenvolvedores Kotlin para sua próxima fase de evolução.\nQuando se fala em software empresarial no Brasil, TOTVS é praticamente sinônimo. A empresa tem presença em mais de 40 mil clientes e suas soluções rodam no coração operacional de empresas que movimentam a economia brasileira.\nAtuação no Brasil e posição de mercado A TOTVS é organizada em três grandes dimensões de negócio:\nGestão: ERPs e sistemas de gestão para diversos segmentos verticais, incluindo manufatura, agronegócio, varejo, saúde, educação, logística, construção civil e serviços. A TOTVS não oferece um ERP genérico — ela tem soluções especializadas que entendem as particularidades de cada setor. Isso é o que a diferencia de concorrentes globais como SAP e Oracle, que muitas vezes não contemplam as especificidades do mercado brasileiro.\nBusiness Performance: soluções de CRM, analytics e inteligência de dados que ajudam empresas a tomar decisões mais informadas. Inclui ferramentas de automação de marketing, gestão de relacionamento com clientes e dashboards gerenciais.\nTechfin: em parceria com o Itaú, a TOTVS opera no segmento de serviços financeiros para empresas, oferecendo crédito, antecipação de recebíveis e outros produtos financeiros integrados diretamente nos sistemas de gestão.\nNo mercado de ERP brasileiro, a TOTVS detém a maior fatia com ampla margem. Sua penetração em médias empresas é particularmente forte, segmento que concorrentes internacionais historicamente têm dificuldade de atender com a mesma profundidade.\nComo a TOTVS usa Kotlin A TOTVS está em um processo intenso de modernização tecnológica. Seus sistemas legados, muitos escritos em linguagens como ADVPL (linguagem proprietária da TOTVS), Progress e Delphi, estão sendo gradualmente migrados para plataformas modernas. Kotlin entra nesse contexto como uma das linguagens escolhidas para a nova geração de produtos.\nNo desenvolvimento mobile, a TOTVS utiliza Kotlin para aplicativos Android voltados a gestão empresarial. Pense em apps que permitem ao gestor de uma fábrica acompanhar a produção pelo celular, ao dono de um restaurante controlar o estoque em tempo real ou ao vendedor externo registrar pedidos em campo. Esses aplicativos precisam funcionar offline (muitos clientes da TOTVS estão em regiões com conectividade limitada), sincronizar dados de forma confiável e apresentar interfaces intuitivas para usuários que não são nativos digitais.\nNo backend, Kotlin é utilizado com Spring Boot na construção de APIs e microsserviços que compõem a TOTVS Cloud, a plataforma de nuvem da empresa. A migração de sistemas de gestão para a nuvem é um dos maiores projetos de engenharia da TOTVS, e novos serviços são frequentemente desenvolvidos em Kotlin, aproveitando a robustez do ecossistema JVM e a produtividade que a linguagem oferece.\nA empresa também investe em Kotlin para desenvolver integrações e conectores entre seus diferentes sistemas, APIs para parceiros do ecossistema e componentes de sua plataforma de extensibilidade que permite que clientes e integradores customizem os produtos TOTVS.\nStack tecnológica e cultura de engenharia O stack da TOTVS é diverso, refletindo décadas de evolução tecnológica:\nBackend moderno: Kotlin e Java com Spring Boot, Node.js para BFFs (Backend for Frontend), .NET em alguns produtos específicos Legado em modernização: ADVPL (Protheus), Progress (Datasul), Delphi — sendo gradualmente encapsulado por APIs modernas Mobile: Kotlin para Android, Swift para iOS, Flutter para projetos multiplataforma Cloud: plataforma TOTVS Cloud baseada em Kubernetes, com operação multi-cloud (AWS e Azure) Dados e IA: Carol (plataforma de dados e inteligência artificial da TOTVS), machine learning para previsão de demanda, análise de crédito e otimização de processos Frontend: React e Angular nos produtos web modernos A cultura de engenharia da TOTVS combina a solidez de uma empresa com mais de 40 anos de mercado com a busca por inovação contínua. A empresa mantém centros de desenvolvimento em São Paulo, Joinville, Belo Horizonte, Goiânia e diversas outras cidades brasileiras, o que cria oportunidades para devs em diferentes regiões do país.\nA TOTVS adota metodologias ágeis com squads multidisciplinares e investe em DevOps e práticas de CI/CD para acelerar entregas. A empresa mantém um programa chamado TOTVS Labs que funciona como um braço de inovação, explorando tecnologias emergentes como IA generativa e blockchain aplicados a gestão empresarial.\nOportunidades de carreira Com mais de 5 mil vagas frequentemente abertas, a TOTVS é uma das empresas que mais contrata profissionais de tecnologia no Brasil. Para desenvolvedores Kotlin, as oportunidades abrangem desde o desenvolvimento de novos produtos mobile até a modernização de sistemas legados em plataformas cloud-native.\nO pacote de benefícios inclui plano de saúde e odontológico, vale-refeição e alimentação, participação nos lucros, previdência privada, Gympass e auxílio educação. A TOTVS oferece acesso à sua própria universidade corporativa, com trilhas de formação técnica e de liderança.\nO modelo de trabalho é híbrido na maioria dos times, com escritórios equipados para colaboração presencial. A diversidade geográfica dos centros de desenvolvimento é um diferencial: enquanto muitas empresas de tecnologia concentram tudo em São Paulo, a TOTVS oferece oportunidades em Joinville, Belo Horizonte, Goiânia, Caxias do Sul e outras cidades, o que é ótimo para quem busca qualidade de vida fora dos grandes centros.\nA trilha de carreira é bem estruturada, com níveis técnicos claramente definidos e avaliações de desempenho semestrais. A empresa valoriza tanto o crescimento técnico quanto a liderança, oferecendo caminhos para ambas as direções.\nPor que um dev Kotlin deveria olhar para a TOTVS A TOTVS oferece uma combinação única no mercado brasileiro: a estabilidade de uma empresa consolidada com o dinamismo de quem está no meio de uma transformação tecnológica massiva. Se você é dev Kotlin, vai ter a oportunidade de participar da modernização dos sistemas que fazem a economia brasileira funcionar.\nO impacto do seu trabalho na TOTVS é tangível. Os sistemas que você vai ajudar a construir são usados diariamente por milhões de profissionais em empresas de todo o Brasil — do agricultor que gerencia sua safra ao gerente de loja que controla seu estoque. Poucas empresas oferecem essa amplitude de impacto no mundo real.\nAlém disso, a escala de contratação da TOTVS significa que as chances de encontrar uma vaga que se encaixe no seu perfil são altas. Seja você um dev júnior buscando seu primeiro emprego em Kotlin ou um sênior querendo liderar a arquitetura de novos produtos cloud-native, a TOTVS provavelmente tem uma oportunidade para você.\nConfira as vagas Acesse o site da TOTVS e veja as posições abertas: https://totvs.com\n","permalink":"https://kotlin.dev.br/empresas/totvs/","summary":"\u003ch2 id=\"totvs-a-maior-empresa-de-software-do-brasil-adota-kotlin-para-modernizar-o-mercado\"\u003eTOTVS: a maior empresa de software do Brasil adota Kotlin para modernizar o mercado\u003c/h2\u003e\n\u003cp\u003eA TOTVS é a maior empresa de tecnologia do Brasil e a líder absoluta em software de gestão empresarial na América Latina. Fundada em 1983 em São Paulo, a empresa acumula mais de quatro décadas de experiência atendendo empresas de todos os portes e segmentos — do pequeno comércio de bairro à grande indústria. Com mais de 16 mil colaboradores e mais de 5 mil vagas tipicamente abertas, a TOTVS está em constante crescimento e busca desenvolvedores Kotlin para sua próxima fase de evolução.\u003c/p\u003e","title":"TOTVS — Empresa que Usa Kotlin no Brasil"},{"content":"Vivo: a maior operadora de telecomunicações do Brasil A Vivo, marca comercial da Telefônica Brasil, é a maior empresa de telecomunicações do país. Com quase 40 mil colaboradores e mais de 100 milhões de acessos entre telefonia móvel, fixa, banda larga e TV por assinatura, a Vivo está presente na vida de uma parcela significativa da população brasileira. A empresa é subsidiária do grupo espanhol Telefónica, um dos maiores conglomerados de telecomunicações do mundo, mas sua operação brasileira tem uma identidade própria e uma estratégia tecnológica que reflete as necessidades específicas do mercado local.\nA Vivo passou por uma transformação importante nos últimos anos. De operadora de telefonia tradicional, a empresa se reposicionou como uma plataforma digital de serviços. Além da conectividade, a Vivo oferece serviços de cloud computing, cibersegurança, IoT (Internet das Coisas), soluções de dados e entretenimento digital. Essa diversificação exige uma área de tecnologia cada vez maior e mais sofisticada.\nA presença da Vivo no mercado brasileiro A Vivo opera a maior rede de telecomunicações do Brasil. É líder em telefonia móvel, com a maior base de clientes do país, e possui a rede de fibra óptica mais extensa do mercado brasileiro. A empresa foi pioneira na implantação do 5G em diversas capitais e está investindo bilhões de reais na expansão da cobertura de fibra óptica para cidades de médio porte.\nPara o mercado corporativo, a Vivo oferece soluções de cloud (Vivo Cloud), cibersegurança, big data, IoT industrial e conectividade dedicada. A empresa atende desde pequenos negócios até as maiores corporações do país, posicionando-se como parceira tecnológica estratégica. O braço de negócios digitais da Vivo — Vivo Digital — concentra as iniciativas de inovação e novos serviços.\nA empresa também atua no setor de entretenimento, com parcerias para oferta de serviços de streaming, e no mercado financeiro, com a Vivo Money, que oferece empréstimos pessoais, e o Vivo Pay, plataforma de pagamentos. Essa expansão para novos mercados cria uma demanda constante por desenvolvimento de software.\nComo a Vivo utiliza Kotlin Com uma operação digital dessa magnitude, a Vivo precisa de linguagens de programação modernas que entreguem produtividade e confiabilidade. Kotlin é utilizado em diversas frentes dentro da empresa.\nNo desenvolvimento mobile, o Kotlin é a linguagem do aplicativo Vivo para Android — o app que dezenas de milhões de brasileiros usam para gerenciar seus planos, consultar consumo de dados, pagar faturas, recarregar créditos e contratar serviços adicionais. A escala de uso é impressionante: o app precisa funcionar em uma diversidade enorme de dispositivos Android, desde smartphones de entrada até os topos de linha, e o Kotlin permite que o time de desenvolvimento escreva código eficiente e compatível com essa fragmentação.\nNo backend, a Vivo emprega Kotlin em microsserviços que sustentam plataformas como o Vivo Pay, o Vivo Money e os sistemas de autoatendimento digital. Esses serviços processam milhões de transações diárias e precisam operar com latência mínima e alta disponibilidade. Kotlin com Spring Boot e Ktor é usado para construir APIs que se integram com sistemas de billing, CRM, orquestração de rede e gateways de pagamento.\nA empresa também utiliza Kotlin em soluções de IoT e edge computing. Dispositivos conectados — como medidores inteligentes, sensores industriais e equipamentos de rede — geram dados que precisam ser processados e analisados em tempo real. Microsserviços escritos em Kotlin consomem esses dados via Kafka e alimentam dashboards, alertas e sistemas de automação.\nOutra área de aplicação é o desenvolvimento de SDKs e APIs para parceiros. A Vivo disponibiliza interfaces de programação para que empresas integrem serviços de telecomunicações em seus próprios produtos, e parte dessas ferramentas é desenvolvida em Kotlin.\nStack tecnológica e cultura de engenharia O stack da Vivo reflete a complexidade de uma operadora de telecomunicações que também é uma empresa de tecnologia digital. Além de Kotlin e Java, os times trabalham com Python, Go, Node.js, React, Angular, Swift, bancos de dados Oracle, PostgreSQL, Cassandra e Elasticsearch, infraestrutura em nuvem com AWS, Azure e Google Cloud (além da própria Vivo Cloud), containers Docker, Kubernetes, Terraform, Kafka, RabbitMQ e ferramentas de observabilidade como Prometheus, Grafana e Splunk.\nA Vivo possui uma estrutura de tecnologia segmentada por domínios: digital consumer, digital B2B, infraestrutura de rede, dados e analytics, e plataformas internas. Cada domínio tem seus times de engenharia com autonomia técnica, mas compartilha práticas e padrões definidos por uma equipe de arquitetura corporativa.\nA cultura de engenharia da Vivo é influenciada tanto pela agilidade das empresas de tecnologia quanto pela governança típica de grandes corporações. Os times adotam Scrum e SAFe (Scaled Agile Framework) para coordenar entregas em escala. Code reviews, testes automatizados, pipelines de CI/CD e deploy canário são práticas estabelecidas. A empresa investe em programas de formação técnica, certificações cloud e parcerias com universidades.\nOportunidades de carreira na Vivo A Vivo é, de longe, um dos maiores empregadores de tecnologia do Brasil, com mais de 6 mil vagas abertas regularmente. As oportunidades abrangem desenvolvimento mobile, backend, frontend, full-stack, engenharia de dados, data science, machine learning, DevOps, SRE, segurança da informação, arquitetura de soluções, gestão de produtos digitais e liderança técnica.\nPara desenvolvedores Kotlin, as posições mais frequentes incluem engenheiro Android sênior e engenheiro backend. A empresa busca profissionais com experiência em desenvolvimento de aplicações de alta escala, conhecimento em arquitetura de microsserviços, familiaridade com cloud computing e práticas de engenharia de software. Experiência com telecomunicações não é obrigatória — a Vivo contrata profissionais de diversos setores e oferece onboarding para o domínio de negócio.\nOs benefícios incluem PLR, plano de saúde e odontológico, vale-refeição e alimentação, auxílio home office, smartphone corporativo com plano Vivo ilimitado, previdência privada, seguro de vida, Gympass, descontos em serviços Vivo e programas de educação continuada. O modelo de trabalho é predominantemente híbrido, com escritórios em São Paulo, Rio de Janeiro, Curitiba e outras capitais.\nPor que um dev Kotlin deveria considerar a Vivo Trabalhar na Vivo é ter a oportunidade de impactar a conectividade de mais de 100 milhões de brasileiros. Telecomunicações é infraestrutura essencial, e o código que você escreve na Vivo literalmente mantém o Brasil conectado.\nA escala dos desafios técnicos é difícil de encontrar em outras empresas. Poucos lugares no país processam o volume de dados e transações que a Vivo processa diariamente. Para um desenvolvedor Kotlin que busca trabalhar em sistemas de missão crítica e alta escala, o ambiente é extremamente rico.\nA diversidade de domínios dentro da empresa — telecomunicações, fintech, IoT, cloud, entretenimento — garante que a carreira nunca fique estagnada. Você pode transitar entre áreas sem trocar de empregador, acumulando experiências diversas. E o respaldo de uma multinacional do porte da Telefónica oferece estabilidade financeira e acesso a tecnologias de ponta.\nConfira as vagas em vivo.com.br e no LinkedIn da Vivo.\n","permalink":"https://kotlin.dev.br/empresas/vivo-telef-nica-brasil/","summary":"\u003ch2 id=\"vivo-a-maior-operadora-de-telecomunicações-do-brasil\"\u003eVivo: a maior operadora de telecomunicações do Brasil\u003c/h2\u003e\n\u003cp\u003eA Vivo, marca comercial da Telefônica Brasil, é a maior empresa de telecomunicações do país. Com quase 40 mil colaboradores e mais de 100 milhões de acessos entre telefonia móvel, fixa, banda larga e TV por assinatura, a Vivo está presente na vida de uma parcela significativa da população brasileira. A empresa é subsidiária do grupo espanhol Telefónica, um dos maiores conglomerados de telecomunicações do mundo, mas sua operação brasileira tem uma identidade própria e uma estratégia tecnológica que reflete as necessidades específicas do mercado local.\u003c/p\u003e","title":"Vivo (Telefônica Brasil) — Empresa que Usa Kotlin no Brasil"}]