Переход на новый язык может быть сложной задачей. Чтобы добиться успеха, начните с небольших изменений, вносите их постепенно и часто тестируйте, чтобы убедиться, что все члены команды понимают, что происходит. Перейти на Kotlin очень просто, поскольку он компилируется в байт-код JVM и полностью совместим с Java.
Создание команды
Прежде чем переносить данные, убедитесь, что у всех членов вашей команды есть общее понимание базовых принципов. Вот несколько советов, которые помогут вам ускорить обучение команды.
Группы по изучению форм
Учебные группы помогают лучше усваивать и запоминать информацию. Исследования показывают, что повторение изученного материала в группе помогает лучше его запомнить. Купите книгу по Kotlin или другие учебные материалы для каждого участника группы и попросите их изучать по несколько глав в неделю. На каждой встрече группа должна сравнивать полученные знания и обсуждать вопросы и наблюдения.
Создайте культуру обучения
Не все считают себя учителями, но каждый может научить чему-то других. Каждый может создать атмосферу, способствующую обучению и успеху, независимо от того, является ли он руководителем команды или отдельным сотрудником. Один из способов сделать это – проводить периодические презентации, на которых один из членов команды рассказывает о том, что он узнал или чем хочет поделиться. Вы можете попросить участников группы по очереди представлять новую главу каждую неделю, пока ваша команда не начнет чувствовать себя уверенно в использовании языка.
Назначьте ответственного за жетоны
Наконец, назначьте ответственного за обучение. Этот пользователь может выступать в качестве профильного эксперта (SME) на начальном этапе внедрения. Важно приглашать этого человека на все тренировочные встречи, связанные с Kotlin. Желательно, чтобы этот человек уже был увлечен Kotlin и имел некоторые практические знания.
Постепенно внедряйте изменения
Важно начать с малого и стратегически продумать, какие части экосистемы перенести в первую очередь. Чаще всего лучше выбрать одно приложение, а не флагманское. В каждом случае перенос выбранного приложения будет отличаться, но вот несколько распространенных вариантов, с которых можно начать.
Модель данных
Ваша модель данных, скорее всего, состоит из большого количества информации о состоянии и нескольких методов. В модели данных также могут быть общие методы, такие как toString(), equals() и hashcode(). Эти методы обычно легко переносятся и тестируются по отдельности.
Предположим, у вас есть следующий фрагмент кода на 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 + '\'' +
'}';
}
}
Класс Java можно заменить одной строкой кода Kotlin, как показано ниже:
data class Person(var firstName: String?, var lastName: String?)
После этого код можно протестировать с помощью текущего набора тестов. Идея заключается в том, чтобы начать с малого, с одной модели за раз, и переносить классы, которые в основном представляют собой состояние, а не поведение. Не забывайте тестировать приложение на разных этапах разработки.
Перенос тестов
Ещё один вариант – преобразовать существующие тесты и начать писать новые на Kotlin. Это даст вашей команде время освоиться с языком, прежде чем писать код, который вы планируете включить в приложение.
Перенесите вспомогательные методы в функции расширения
Любые статические вспомогательные классы (StringUtils, IntegerUtils, DateUtils, YourCustomTypeUtils и т. д.) можно представить в виде функций-расширений Kotlin и использовать в существующей базе кода Java.
Предположим, у вас есть класс StringUtils с несколькими методами:
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
}
}
Эти методы могут использоваться в других частях приложения, как показано в следующем примере:
...
String myString = ...
String fooString = StringUtils.foo(myString);
...
Используя функции-расширения Kotlin, вы можете предоставить вызывающим объектам Java тот же интерфейс Utils, одновременно предлагая более краткий API для растущей базы кода Kotlin.
Для этого можно начать с преобразования класса Utils в Kotlin с помощью автоматического преобразования, предоставляемого IDE. Пример выходных данных:
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
}
}
Затем удалите определение класса или объекта, добавьте к каждому имени функции префикс типа, к которому должна применяться эта функция, и используйте этот префикс для ссылки на тип внутри функции, как показано в следующем примере:
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
}
Наконец, добавьте аннотацию JvmName в начало исходного файла, чтобы скомпилированное имя было совместимо с остальной частью приложения, как показано в следующем примере:
@file:JvmName("StringUtils")
package com.java.project
...
Окончательный вариант должен выглядеть примерно так:
@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
}
Обратите внимание, что теперь эти функции можно вызывать с помощью Java или Kotlin, используя соглашения, соответствующие каждому языку.
Kotlin
// ... val myString: String = "hello" val fooString = myString.foo() // ...
Java
... String myString = ... String fooString = StringUtils.foo(myString); ...
Как завершить перенос
Когда ваша команда освоит Kotlin и вы перенесете небольшие участки кода, можно будет перейти к более крупным компонентам, таким как фрагменты, действия, объекты ViewModel и другие классы, связанные с бизнес-логикой.
Что нужно учесть
Как и у Java, у Kotlin есть собственный стиль, который делает код более лаконичным. Однако на начальном этапе код Kotlin, который создает ваша команда, может быть похож на код Java, который он заменяет. Это значение может меняться по мере того, как ваша команда будет приобретать опыт работы с Kotlin. Помните, что успех приходит постепенно.
Вот несколько способов обеспечить единообразие по мере роста базы кода Kotlin:
Распространенные стандарты кодирования
Определите стандартный набор правил написания кода на ранних этапах внедрения. Вы можете отклоняться от руководства по стилю Kotlin для Android, если это целесообразно.
Инструменты статического анализа
Используйте Android lint и другие инструменты статического анализа, чтобы обеспечить соблюдение стандартов кодирования, установленных для вашей команды. Сторонний линтер Kotlin klint также предоставляет дополнительные правила для Kotlin.
Непрерывная интеграция
Соблюдайте общепринятые стандарты кодирования и обеспечьте достаточный охват тестами для кода Kotlin. Если включить этот этап в автоматизированный процесс сборки, можно обеспечить единообразие и соблюдение стандартов.
Совместимость
В большинстве случаев Kotlin и Java работают вместе без проблем, но обратите внимание на следующее.
Допускает значение NULL
Kotlin использует аннотации о допустимости значения NULL в скомпилированном коде, чтобы определять допустимость значения NULL в коде Kotlin. Если аннотации не указаны, Kotlin по умолчанию использует платформенный тип, который можно рассматривать как допускающий или не допускающий значение NULL. Однако при неправильном использовании это может привести к проблемам с NullPointerException во время выполнения.
Как использовать новые функции
В Kotlin есть множество новых библиотек и синтаксических конструкций, которые позволяют сократить количество стандартного кода и ускорить разработку. Однако при использовании функций стандартной библиотеки Kotlin, таких как функции коллекций, корутины и лямбды, следует проявлять осторожность и методичность.
Вот распространенная ошибка, которую часто допускают начинающие разработчики на Kotlin. Предположим, что у вас есть следующий код 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() }
В этом примере намерение состоит в том, чтобы выполнить foo.baz() и foo.zap(), если nullableFoo не равно null, чтобы избежать NullPointerException. Хотя этот код работает как ожидается, его сложнее читать, чем простой код с проверкой на null и умным приведением типов, как показано в следующем примере:
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 }
Тестирование
В Kotlin классы и их функции по умолчанию закрыты для расширения. Вам нужно явно открыть классы и функции, которые вы хотите создать как подкласс. Такое поведение обусловлено особенностями языка, в котором приоритет отдается композиции, а не наследованию. В Kotlin встроена поддержка реализации поведения с помощью делегирования, что упрощает композицию.
Такое поведение создает проблему для фреймворков для создания заглушек, например Mockito, которые полагаются на реализацию интерфейса или наследование для переопределения поведения во время тестирования. Для модульных тестов можно включить использование функции Mock Maker Inline библиотеки Mockito, которая позволяет имитировать конечные классы и методы. Вы также можете использовать плагин компилятора All-Open, чтобы открыть любой класс Kotlin и его элементы, которые вы хотите протестировать в процессе компиляции. Основное преимущество этого плагина в том, что он работает как с модульными, так и с инструментальными тестами.
Дополнительная информация
Чтобы узнать больше о Kotlin, перейдите по ссылкам ниже.
- Подход Android к разработке на Kotlin
- Ресурсы для начала работы с Kotlin
- Ресурсы для пользователей Java, изучающих Kotlin
- Путь обучения Java–Kotlin – это набор ресурсов, которые помогут программистам на Java изучить Kotlin и писать на нем идиоматический код.