新しい言語への移行は困難な場合があります。チームを成功に導くには、ゆっくりと開始し、小さなチャンクで移行して、頻繁にテストします。Kotlin は JVM バイトコードにコンパイルされ、Java との完全な相互運用性があるため、移行が容易になります。
チームの構築
移行前の最初のステップは、チーム内で共通の基本的理解を構築することです。ここでは、チームの学習促進に役立つヒントをいくつかご紹介します。
学習グループの形成
学習グループは、学習と定着を円滑に進めるための効果的な方法です。調査によると、学んだことをグループで復唱すると、教材の理解が深まります。グループの各メンバーに Kotlin の書籍などの学習資料を用意し、毎週数章を読むようグループに指示してください。それぞれの会合において、グループ内で、学んだ内容を比較し、質問や意見を話し合うとよいでしょう。
教える文化を築く
人に教えるのがうまいと自覚している人は少ないとしても、教えることは誰にでもできます。テクノロジー リーダーやチームリーダーから個々のコントリビューターに至るまで、誰もが成功に役立つ学習環境を推進できます。それを円滑に進める方法の 1 つとして、チームの 1 人を指名して学んだことや共有したいことを話してもらうプレゼンテーションを定期的に行うことが挙げられます。新しい章のプレゼンテーションをする有志を、チームが言語に慣れるまで毎週募ることで、学習グループを活用できます。
チャンピオンを指名する
最後に、学習の取り組みをリードするチャンピオンを指名します。導入プロセスを開始する際には、この人物がチームリード(SME)の役割を果たすことができます。Kotlin に関連するすべての練習会にこの人物を含めることが重要です。チャンピオンとしては、すでに Kotlin に興味を持ち、ある程度の実践的知識を持っている人物が理想的です。
時間をかけて統合する
重要なのは、初めに時間をかけて、エコシステムのどの部分を最初に動かすべきかを戦略的に考えることです。これは多くの場合、主要アプリではなく組織内の 1 つのアプリを特定して行うのが効果的です。選択したアプリの移行について、状況がそれぞれ異なることを前提に、一般的なスタート ポイントをいくつか紹介します。
データモデル
データモデルは、たいていの場合、多くの状態情報といくつかのメソッドで構成されています。データモデルには、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 クラスを 1 行の Kotlin に置き換えることができます。
data class Person(var firstName: String?, var lastName: String?)
その後、現在のテストスイートに対してこのコードの単体テストを行うことができます。一度に 1 つのモデルから始めて、動作ではなく状態がほとんどのクラスを移行します。途中で頻繁にテストします。
テストを移行する
テストから始めることもできます。既存のテストを変換し、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 インターフェースを提供しながら、増大する Kotlin コードベースに簡潔な API を提供できます。
これを行うには、IDE によって提供される自動変換を使ってこの Utils クラスを Kotlin に変換することから始めてもよいでしょう。出力例は次のようになります。
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 lint などの静的分析ツールを使用して、チームに設定されたコーディング標準を適用します。サードパーティの Kotlin リンターである ktlint にも、Kotlin 用の追加ルールが用意されています。
継続的インテグレーション
必ず共通のコーディング標準に則り、Kotlin コードを十分にテストしてください。これを自動化ビルドプロセスの一環として行うと、これらの標準の一貫性と遵守を確保できます。
相互運用性
Kotlin はほとんどの場合、Java とシームレスに相互運用できますが、次の点に注意してください。
null 可能性
Kotlin は、コンパイル済みコードの null 値許容アノテーションを利用して、Kotlin 側での null 値許容を推測します。アノテーションが指定されていない場合、Kotlin はデフォルトで、null 値許容型または 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() }
この例の目的は、nullableFoo が null でない場合に foo.baz と foo.zap を実行し、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 がこの選択を行うのは、継承よりもコンポジションを促進するためです。コンポジションを簡素化するため、Kotlin には委任を通じて動作を実装するための組み込みサポートがあります。
この動作は、テスト中にインターフェースの実装や継承に依存して動作をオーバーライドするモック フレームワーク(Mockito など)で問題を引き起こします。単体テストでは、Mockito の Mock Maker Inline 機能の使用を有効にできます。これにより、final クラスと final メソッドをモックできます。または、All-Open コンパイラ プラグインを使用して、コンパイル プロセスの一部としてテストする Kotlin クラスとそのメンバーを開くこともできます。このプラグインを使用する主なメリットは、単体テストとインストゥルメント化テストの両方に有効である点にあります。
詳細
Kotlin の使用について詳しくは、以下のリンクをご覧ください。
- Android の Kotlin ファースト アプローチ
- Kotlin を使い始めるための参考情報
- Kotlin を学ぶ Java ユーザー向けの参考資料
- Java から Kotlin への学習パスウェイ。Java プログラマーが慣用的な Kotlin を学習し、記述するのに役立つ参考情報を集めたものです。