A mudança para uma nova linguagem pode ser desafiadora. Para preparar sua equipe para o sucesso, comece devagar, migre em pequenos blocos e teste com frequência. O Kotlin é compilado para bytecode da JVM e é totalmente interoperável com o Java, o que facilita a migração.
Como montar a equipe
A primeira etapa antes da migração é criar um entendimento básico comum para a equipe. Veja algumas dicas que podem ser úteis para acelerar o aprendizado das equipes.
Formar grupos de estudo
Grupos de estudo são uma maneira eficaz de facilitar a aprendizagem e a absorção. Estudos sugerem que recitar o que você aprendeu em um ambiente de grupo ajuda a reforçar o material. Compre um livro sobre Kotlin ou outro material de estudo para cada participante e peça ao grupo para estudar alguns capítulos por semana. Durante cada reunião, o grupo pode comparar o que aprendeu e fazer perguntas ou observações.
Construir uma cultura de aprendizagem
Embora nem todo mundo se considere professor, todos podem transmitir conhecimento. Desde um líder de tecnologia ou líder da equipe a um colaborador individual, todos podem incentivar um ambiente de aprendizagem que pode ajudar a garantir o sucesso. Uma maneira de facilitar isso é fazer apresentações periódicas, em que uma pessoa da equipe é designada para falar sobre algo que aprendeu ou que gostaria de compartilhar. Você pode aproveitar o grupo de estudo e pedir que voluntários apresentem um novo capítulo a cada semana até chegar a um ponto em que a equipe se sinta confortável com a linguagem.
Indicar uma liderança
Por fim, indique uma liderança para conduzir o processo de aprendizagem. Essa pessoa poderá atuar como um especialista no assunto (SME, na sigla em inglês) quando você iniciar o processo de adoção. É importante incluir essa pessoa em todas as reuniões práticas relacionadas ao Kotlin. O ideal é que essa pessoa já esteja envolvida com o Kotlin e tenha algum conhecimento prático.
Integrar lentamente
É fundamental começar devagar e pensar estrategicamente sobre quais partes do seu ecossistema precisam mudar primeiro. Muitas vezes, é melhor isolar esse processo em um app único na sua organização, em vez de em um app principal. Em termos de migração do app escolhido, cada situação é diferente, mas estes são alguns pontos comuns para começar.
Modelo de dados
Provavelmente, seu modelo de dados consiste em muitas informações de estado e alguns métodos. O modelo de dados também pode ter métodos comuns, como toString, equals e hashCode. Geralmente, é possível migrar esses métodos e testá-los em teste de unidade isoladamente.
Por exemplo, considere o seguinte snippet de Java:
public class Person {
private String firstName;
private String lastName;
// ...
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(firstName, person.firstName) &&
Objects.equals(lastName, person.lastName);
}
@Override
public int hashCode() {
return Objects.hash(firstName, lastName);
}
@Override
public String toString() {
return "Person{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
}
É possível substituir a classe Java por uma única linha de Kotlin, conforme mostrado no exemplo a seguir:
data class Person(var firstName: String?, var lastName: String?)
Em seguida, você pode testar esse código em unidade no seu conjunto de testes atual. Comece aos poucos, com um modelo por vez, e migre classes que sejam principalmente de estado, em vez de comportamento. Teste com frequência ao longo do caminho.
Migrar testes
Outro lugar para começar são seus testes: converta os testes atuais e escreva novos testes em Kotlin. Isso dá à sua equipe tempo para se familiarizar com a linguagem antes de escrever o código que é enviado com o app.
Mover métodos utilitários para funções de extensão
É possível representar classes de utilitários estáticos, como StringUtils,
IntegerUtils, DateUtils, ou YourCustomTypeUtils, como
funções de extensão do Kotlin
e usá-las na sua base de código Java atual.
Por exemplo, considere que você tem uma classe StringUtils com alguns métodos:
package com.java.project;
public class StringUtils {
public static String foo(String receiver) {
return receiver...; // Transform the receiver in some way
}
public static String bar(String receiver) {
return receiver...; // Transform the receiver in some way
}
}
Esses métodos podem ser usados em outro lugar no app, como mostrado no exemplo a seguir:
...
String myString = ...
String fooString = StringUtils.foo(myString);
...
Usando funções de extensão do Kotlin, você pode fornecer a mesma interface Utils para chamadores Java, além de oferecer uma API mais sucinta para sua base de código Kotlin em crescimento.
Para fazer isso, você pode começar convertendo essa classe Utils em Kotlin usando a conversão automática fornecida pelo ambiente de desenvolvimento integrado. A saída de exemplo pode ser semelhante a esta:
package com.java.project
object StringUtils {
fun foo(receiver: String): String {
return receiver...; // Transform the receiver in some way
}
fun bar(receiver: String): String {
return receiver...; // Transform the receiver in some way
}
}
Em seguida, remova a definição de classe ou objeto, prefixe cada nome de função com o tipo em que essa função se aplica e use-a para fazer referência ao tipo dentro da função, como mostrado no exemplo a seguir:
package com.java.project
fun String.foo(): String {
return this...; // Transform the receiver in some way
}
fun String.bar(): String {
return this...; // Transform the receiver in some way
}
Por fim, adicione uma anotação JvmName à parte superior do arquivo fonte para tornar o nome compilado compatível com o restante do app, como mostrado no exemplo a seguir:
@file:JvmName("StringUtils")
package com.java.project
...
A versão final se parecerá com esta:
@file:JvmName("StringUtils")
package com.java.project
fun String.foo(): String {
return this...; // Transform `this` string in some way
}
fun String.bar(): String {
return this...; // Transform `this` string in some way
}
Essas funções agora podem ser chamadas usando Java ou Kotlin com convenções que correspondem a cada linguagem.
Kotlin
// ... val myString: String = "hello" val fooString = myString.foo() // ...
Java
... String myString = ... String fooString = StringUtils.foo(myString); ...
Conclua a migração
Depois que sua equipe estiver confortável com o Kotlin e você tiver migrado áreas menores, poderá passar para componentes maiores, como fragmentos, atividades, objetos ViewModel e outras classes relacionadas à lógica de negócios.
Considerações
Assim como o Java tem um estilo específico, o Kotlin tem um estilo idiomático próprio que contribui para a concisão. No entanto, no início, você pode descobrir que o código Kotlin que sua equipe escreve se parece mais com o código Java que está substituindo. Isso muda à medida que sua equipe ganha experiência com o Kotlin. A mudança gradual é a chave para o sucesso.
Confira algumas coisas que você pode fazer para manter a base de código Kotlin consistente à medida que ela cresce:
Padrões comuns de programação
Defina um conjunto padrão de convenções de programação logo no início do processo de adoção. Você pode divergir do guia de estilo Kotlin do Android onde fizer sentido.
Ferramentas de análise estática
Aplique os padrões de programação definidos para sua equipe usando o lint do Android e outras ferramentas de análise estática. O ktlint, um linter Kotlin de terceiros, também fornece regras adicionais para o Kotlin.
Integração contínua
Siga padrões de programação comuns e forneça cobertura de teste suficiente para o código Kotlin. Fazer isso, em um processo de criação automatizado, pode ajudar a garantir a consistência e a aderência a esses padrões.
Interoperabilidade
O Kotlin interopera com o Java de maneira integrada na maior parte do tempo, mas tenha em mente os pontos a seguir.
Nulidade
O Kotlin depende de anotações de nulidade no código compilado para inferir a capacidade de anulação no lado do Kotlin. Se as anotações não forem fornecidas, o Kotlin vai usar um tipo de plataforma padrão que pode ser tratado como anulável ou não anulável. Se você não processar os tipos de plataforma com cuidado, isso poderá levar a problemas de NullPointerException de execução.
Adotar novos recursos
O Kotlin oferece muitas novas bibliotecas e açúcar sintático para reduzir o boilerplate, o que ajuda a aumentar a velocidade de desenvolvimento. Dito isso, tenha uma abordagem cautelosa e metódica ao usar as funções de biblioteca padrão do Kotlin, como funções de coleção, corrotinas e lambdas.
Confira uma armadilha comum em que os desenvolvedores que estão começando a usar o Kotlin caem. Considere o seguinte código Kotlin:
val nullableFoo: Foo? = Foo() // This lambda executes only if nullableFoo is not null // and `foo` is of the non-nullable Foo type nullableFoo?.let { foo -> foo.baz() foo.zap() }
A intenção neste exemplo é executar foo.baz e foo.zap se nullableFoo não for nulo, evitando assim uma NullPointerException. Embora este
código funcione conforme o esperado, ele é menos intuitivo de ler do que uma verificação nula e uma
conversão inteligente,
conforme mostrado no exemplo a seguir:
val nullableFoo: Foo? = null if (nullableFoo != null) { nullableFoo.baz() // Using !! or ?. isn't required; the Kotlin compiler infers non-nullability nullableFoo.zap() // from guard condition; smart casts nullableFoo to Foo inside this block }
Teste
No Kotlin, as classes e as funções são fechadas para extensão por padrão. Você precisa abrir explicitamente as classes e funções que quer criar subclasses. O Kotlin faz essa escolha para promover a composição em vez da herança. Para simplificar a composição, o Kotlin tem suporte integrado para implementar o comportamento por delegação.
Esse comportamento representa um problema para frameworks de simulação, como o Mockito, que dependem de implementação de interface ou herança para substituir comportamentos durante o teste. Para testes de unidade, é possível ativar o uso do recurso Mock Maker Inline do Mockito, que permite simular classes e métodos finais. Como alternativa, você pode usar o plug-in do compilador All-Open para abrir qualquer classe Kotlin e os membros que você quer testar como parte do processo de compilação. A principal vantagem de usar esse plug-in é que ele funciona com testes de instrumentação e de unidade.
Mais informações
Para mais informações sobre como usar o Kotlin, consulte os links a seguir:
- Abordagem Kotlin do Android
- Outros recursos para começar a usar o Kotlin
- Outros recursos para usuários do Java que estão aprendendo Kotlin
- Caminho de aprendizado Java para Kotlin, uma coleção de recursos que ajudam os programadores Java a aprender e escrever Kotlin idiomático.