Introdução: por que código legado não é uma sentença
\nTodo desenvolvedor já se deparou com código legado — aquela "caixa preta" que você tem medo de tocar porque "está funcionando, não mexa". No entanto, quando a base de código em Kotlin (ou Java, que está sendo gradualmente migrada) começa a atrasar o desenvolvimento, acumular bugs e assustar novos membros da equipe, chega a hora da refatoração. A refatoração de código legado em Kotlin não é apenas reescrever, mas um processo sistemático de melhoria da estrutura interna sem alterar o comportamento externo.
\nNeste artigo, vamos percorrer o caminho completo: desde a análise do estado atual até a implementação de práticas modernas do Kotlin. Você aprenderá como transformar código obsoleto com segurança, usando os recursos da linguagem (nullable, extension functions, sealed classes) sem quebrar a produção.
\n\n1. Diagnóstico: como avaliar a extensão do código legado
\nAntes de iniciar a refatoração, é necessário entender com o que você está lidando. Código legado em Kotlin geralmente vem de projetos que começaram em Java e foram parcialmente migrados. Sinais típicos:
\n- \n
- God-objects — classes que fazem tudo: desde parsing até lógica de negócios. \n
- Falta de testes — código não coberto por testes unitários, e qualquer alteração é arriscada. \n
- Dados mutáveis — abundância de
varem vez deval, listas mutáveis que são passadas entre módulos. \n - Pesadelo com null — operador
!!espalhado por todo o código e verificações infinitas deif (x != null). \n
Para o diagnóstico, use ferramentas: Detekt (análise estática Kotlin), SonarQube (métricas de qualidade) e IntelliJ IDEA Inspections. Crie uma lista de verificação de pontos problemáticos e priorize-os por risco e frequência de uso.
\n\n1.1. Mapeamento de dependências
\nPegue uma folha de papel ou use PlantUML para visualizar as conexões entre as classes. Se o grafo de dependências parece uma teia de aranha — é um sinal de alerta. Preste atenção especial às dependências cíclicas: elas tornam o código frágil e difícil de testar.
\n\n2. Estratégia de refatoração: plano de ação passo a passo
\nRefatoração sem plano é o caminho para o desastre. Use a abordagem "Técnica dos pequenos passos" (baby steps). Algoritmo de ação:
\n- \n
- Documente o comportamento — escreva testes de caracterização (characterization tests) que fixam o comportamento atual do sistema. \n
- Isole as alterações — trabalhe em um branch separado, use feature toggles para partes complexas. \n
- Refatoração por padrões — aplique técnicas comprovadas (Extract Method, Replace Conditional with Polymorphism, Introduce Parameter Object). \n
- Migração gradual — não tente reescrever tudo de uma vez. Use anotações
@Deprecatedpara métodos antigos. \n
2.1. Exemplo: substituindo if-else por when e sealed classes
\nCódigo legado típico em Kotlin contém cadeias de if-else para lidar com estados:
\n// Ruim: flag mutável e if-else\nvar status = "active"\nif (status == "active") {\n // ...\n} else if (status == "inactive") {\n // ...\n} else {\n throw Exception("Unknown status")\n}\nRefatoração com sealed classes:
\n// Bom: modelo type-safe\nsealed class Status {\n object Active : Status()\n object Inactive : Status()\n data class Custom(val reason: String) : Status()\n}\n\nfun handleStatus(status: Status) = when (status) {\n is Status.Active -> // processamento\n is Status.Inactive -> // processamento\n is Status.Custom -> // processamento com reason\n}\nIsso elimina a necessidade de else e torna o código extensível.
3. Trabalho seguro com nullable e coleções
\nCódigo legado frequentemente