Mengadopsi Kotlin untuk tim berukuran besar

Beralih ke bahasa baru bisa jadi sulit. Untuk menyiapkan tim Anda agar berhasil, mulailah secara perlahan, lakukan migrasi dalam bagian-bagian kecil, dan lakukan pengujian secara rutin. Kotlin dikompilasi ke bytecode JVM dan sepenuhnya dapat dioperasikan dengan Java, sehingga mempermudah migrasi.

Membangun tim

Langkah pertama sebelum bermigrasi adalah membangun pemahaman dasar umum untuk tim Anda. Berikut beberapa tips yang mungkin berguna untuk mempercepat proses belajar tim Anda.

Membentuk kelompok belajar

Kelompok belajar merupakan cara yang efektif untuk memfasilitasi pembelajaran dan retensi. Studi menunjukkan bahwa mengulang apa yang telah Anda pelajari dalam kelompok membantu memperkuat pemahaman materi. Dapatkan buku Kotlin atau materi belajar lainnya untuk setiap anggota kelompok, dan mintalah kelompok agar membaca beberapa bab setiap minggunya. Dalam setiap pertemuan, kelompok harus membandingkan apa yang telah mereka pelajari dan mendiskusikan setiap pertanyaan atau pengamatan.

Membangun budaya mengajar

Meskipun tidak semua orang menganggap diri mereka sebagai guru, semua orang dapat mengajar. Mulai dari pemimpin tim atau teknologi hingga kontributor perorangan, semua orang dapat mendorong lingkungan belajar yang dapat membantu menjamin kesuksesan. Salah satu cara untuk memfasilitasi hal ini adalah dengan mengadakan presentasi secara berkala dengan orang dalam tim tersebut ditunjuk untuk membahas sesuatu yang telah mereka pelajari atau ingin mereka sampaikan. Anda bisa memanfaatkan kelompok belajar dengan meminta relawan untuk mempresentasikan bab baru setiap minggu sampai Anda mencapai titik saat tim merasa nyaman dengan bahasa yang dipelajari.

Menunjuk seorang pendukung

Terakhir, tunjuk seorang pendukung untuk memimpin upaya pembelajaran. Orang ini dapat bertindak sebagai pakar materi pokok (SME) saat Anda memulai proses adopsi. Penting untuk menyertakan orang ini dalam semua pertemuan praktik Anda yang berkaitan dengan Kotlin. Idealnya, orang ini sudah menyukai dan memiliki pengetahuan yang cukup tentang Kotlin.

Mengintegrasikan secara perlahan

Memulai secara perlahan dan berpikir strategis terkait bagian ekosistem mana saja yang harus bergerak terlebih dahulu adalah kuncinya. Sebaiknya pisahkan ini ke satu aplikasi dalam organisasi Anda, bukan aplikasi unggulan. Dalam hal memigrasikan aplikasi yang dipilih, setiap situasi sifatnya berbeda, tetapi berikut adalah beberapa area yang umum untuk memulai.

Model data

Model data Anda kemungkinan terdiri dari banyak informasi status beserta dengan beberapa metode. Model data juga dapat memiliki metode umum seperti toString, equals, dan hashCode. Anda biasanya dapat memigrasikan metode ini dan menguji unitnya secara terpisah.

Misalnya, asumsikan cuplikan Java berikut:

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 + '\'' +
               '}';
   }
}

Anda dapat mengganti class Java dengan satu baris Kotlin, seperti yang ditunjukkan pada contoh berikut:

data class Person(var firstName: String?, var lastName: String?)

Kemudian, Anda dapat melakukan pengujian unit pada kode ini terhadap suite pengujian saat ini. Mulailah dari hal kecil dengan satu model dalam satu waktu, dan migrasikan class yang sebagian besar merupakan status, bukan perilaku. Lakukan pengujian secara rutin selama prosesnya.

Memigrasikan pengujian

Tempat lain untuk memulai adalah pengujian Anda: konversi pengujian yang ada dan tulis pengujian baru di Kotlin. Dengan begitu, tim Anda memiliki waktu untuk memahami bahasa tersebut sebelum Anda menulis kode yang dikirimkan bersama aplikasi Anda.

Memindahkan metode utilitas ke fungsi ekstensi

Anda dapat merepresentasikan class utilitas statis, seperti StringUtils, IntegerUtils, DateUtils, atau YourCustomTypeUtils, sebagai fungsi ekstensi Kotlin dan menggunakannya dari codebase Java yang sudah ada.

Misalnya, anggap Anda memiliki class StringUtils dengan beberapa metode:

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
   }

}

Metode ini nantinya dapat digunakan di tempat lain dalam aplikasi Anda, seperti yang ditunjukkan pada contoh berikut:

...

String myString = ...
String fooString = StringUtils.foo(myString);

...

Dengan fungsi ekstensi Kotlin, Anda dapat menyediakan antarmuka Utils yang sama untuk pemanggil Java sekaligus menawarkan API yang lebih ringkas untuk codebase Kotlin Anda yang terus berkembang.

Untuk melakukannya, Anda bisa memulai dengan mengonversi class Utils ini ke Kotlin menggunakan konversi otomatis yang disediakan oleh IDE. Contoh output-nya mungkin terlihat mirip seperti berikut:

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
   }

}

Selanjutnya, hapus definisi class atau objek, awali setiap nama fungsi dengan jenis fungsi mana yang harus diterapkan, dan gunakan ini untuk mereferensikan jenis di dalam fungsi tersebut, seperti yang ditunjukkan pada contoh berikut:

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
}

Terakhir, tambahkan anotasi JvmName ke bagian atas file sumber agar nama yang dikompilasi kompatibel dengan seluruh aplikasi Anda, seperti yang ditunjukkan pada contoh berikut:

@file:JvmName("StringUtils")
package com.java.project
...

Versi akhir akan terlihat seperti berikut:

@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
}

Ingat bahwa fungsi ini sekarang dapat dipanggil menggunakan Java atau Kotlin dengan konvensi yang cocok dengan setiap bahasa.

Kotlin

// ...

val myString: String = "hello"
val fooString = myString.foo()

// ...

Java

...
String myString = ...
String fooString = StringUtils.foo(myString);
...

Menyelesaikan migrasi

Setelah tim Anda memahami Kotlin dan Anda telah memigrasikan area yang lebih kecil, Anda dapat beralih ke komponen yang lebih besar seperti fragmen, aktivitas, objek ViewModel, dan class lain yang terkait dengan logika bisnis.

Pertimbangan

Sama seperti Java yang memiliki gaya spesifik, Kotlin memiliki gaya idiomatisnya sendiri yang berkontribusi pada ringkasnya kode. Namun, pada awalnya, Anda mungkin mendapati bahwa kode Kotlin yang ditulis tim Anda lebih mirip dengan kode Java yang digantikannya. Hal ini akan berubah seiring bertambahnya pengalaman tim Anda dalam menggunakan Kotlin. Perubahan bertahap adalah kunci keberhasilan.

Berikut beberapa hal yang dapat Anda lakukan untuk menjaga konsistensi codebase Kotlin seiring perkembangannya:

Standar coding umum

Pastikan Anda menentukan dari awal sekumpulan konvensi coding standar dalam proses adopsi. Anda boleh tidak begitu menghiraukan panduan gaya Kotlin Android jika hal tersebut logis.

Alat analisis statis

Terapkan standar coding yang ditetapkan untuk tim Anda menggunakan Android lint dan alat analisis statis lainnya. ktlint, linter Kotlin pihak ketiga, juga menyediakan aturan tambahan untuk Kotlin.

Continuous integration

Pastikan sesuai dengan standar coding umum, dan berikan cakupan pengujian yang memadai untuk kode Kotlin Anda. Menjadikan ini bagian dari proses build otomatis dapat membantu memastikan konsistensi dan kepatuhan terhadap standar ini.

Interoperabilitas

Kotlin dapat saling beroperasi dengan Java secara lancar, tetapi perhatikan poin-poin berikut.

Nullability

Kotlin bergantung pada anotasi nullability pada kode yang dikompilasi untuk menyimpulkan nullability pada sistem Kotlin. Jika anotasi tidak diberikan, Kotlin secara default menggunakan jenis platform yang dapat diperlakukan sebagai nullable atau non-nullable. Jika Anda tidak menangani jenis platform dengan hati-hati, hal ini dapat menyebabkan masalah NullPointerException saat runtime.

Menggunakan fitur baru

Kotlin menyediakan banyak library baru dan sugar sintaksis untuk mengurangi boilerplate, yang membantu meningkatkan kecepatan pengembangan. Karena itu, berhati-hatilah dan lakukan berdasarkan metode saat menggunakan fungsi library standar Kotlin, seperti fungsi koleksi, coroutine, dan lambda.

Berikut adalah kesalahan umum yang dialami developer yang baru mengenal Kotlin. Pertimbangkan kode Kotlin berikut:

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()
}

Intent dalam contoh ini adalah untuk mengeksekusi foo.baz dan foo.zap jika nullableFoo bukan null, sehingga menghindari NullPointerException. Meskipun kode ini berfungsi seperti yang diharapkan, kode ini kurang intuitif untuk dibaca daripada pemeriksaan null dan smart cast, seperti yang ditunjukkan dalam contoh berikut:

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
}

Pengujian

Di Kotlin, class dan fungsinya ditutup untuk ekstensi secara default. Anda harus membuka secara eksplisit class dan fungsi yang ingin Anda buat subclass-nya. Kotlin membuat pilihan ini untuk mengutamakan komposisi daripada pewarisan. Untuk membantu menyederhanakan komposisi, Kotlin memiliki dukungan bawaan untuk mengimplementasikan perilaku melalui delegasi.

Perilaku ini menimbulkan masalah bagi framework tiruan, seperti Mockito, yang bergantung pada turunan atau implementasi antarmuka untuk mengganti perilaku selama pengujian. Untuk pengujian unit, Anda dapat mengaktifkan penggunaan fitur Mock Maker Inline Mockito, yang memungkinkan Anda membuat tiruan class dan metode final. Atau, Anda dapat menggunakan plugin compiler All-Open untuk membuka class Kotlin dan anggotanya yang ingin Anda uji sebagai bagian dari proses kompilasi. Keuntungan utama menggunakan plugin ini adalah berfungsi dengan baik pada pengujian unit dan berinstrumen.

Informasi selengkapnya

Untuk informasi selengkapnya tentang cara menggunakan Kotlin, lihat link berikut: