Mengadopsi Kotlin untuk tim berukuran besar

Perpindahan ke bahasa baru dapat jadi proses yang membingungkan. Resep meraih kesuksesan adalah memulai perlahan, berpindah secara bertahap, dan melakukan pengujian lebih sering untuk menyelaraskan tim Anda agar berhasil. Kotlin memudahkan migrasi karena mengompilasi ke bytecode JVM dan dapat dioperasikan sepenuhnya dengan Java.

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 membaca materi yang Anda pelajari secara berkelompok dapat membantu memperkuat 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 pimpinan teknologi atau tim 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 mungkin juga memiliki metode umum seperti toString() equals(), dan hashcode(). Metode ini biasanya dapat ditransisikan dan unit diuji dengan mudah 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 bisa mengganti class Java dengan satu baris Kotlin, seperti yang ditampilkan di sini:

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

Kode ini nantinya dapat diuji di tingkat unit pada rangkaian pengujian Anda saat ini. Intinya adalah memulai dari yang kecil dengan satu model pada satu waktu dan mentransisikan class yang sebagian besar berupa status, bukan perilaku. Pastikan untuk sering melakukan pengujian di sepanjang prosesnya.

Memigrasikan pengujian

Cara lain untuk memulai yang perlu dipertimbangkan adalah mengonversi pengujian yang ada dan mulai menulis pengujian baru dalam Kotlin. Hal ini dapat memberikan waktu bagi tim Anda untuk merasa nyaman dengan bahasa tersebut sebelum menulis kode yang akan dikirim dengan aplikasi Anda.

Memindahkan metode utilitas ke fungsi ekstensi

Semua class utilitas statis (StringUtils, IntegerUtils, DateUtils, YourCustomTypeUtils, dan seterusnya) dapat direpresentasikan sebagai fungsi ekstensi Kotlin dan digunakan oleh 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 menggunakan fungsi ekstensi Kotlin, Anda dapat menyediakan antarmuka Utils yang sama untuk pemanggil Java, sekaligus menawarkan API yang lebih ringkas untuk code base 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 = ...
val fooString = myString.foo()
...

Java

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

Menyelesaikan migrasi

Setelah tim Anda nyaman dengan Kotlin dan Anda berhasil memigrasikan area yang lebih kecil, Anda dapat melanjutkan untuk menangani komponen yang lebih besar seperti fragmen, aktivitas, objek ViewModel, dan class lain yang berkaitan dengan logika bisnis Anda.

Pertimbangan

Sangat mirip dengan Java yang memiliki gaya tertentu, Kotlin memiliki gaya idiomatis tersendiri yang berkontribusi terhadap kesingkatannya. Namun, awalnya Anda mungkin menganggap kode Kotlin yang dihasilkan tim Anda lebih mirip kode Java yang digantikannya. Hal ini akan berubah dari waktu ke waktu seiring bertambahnya pengalaman Kotlin tim Anda. Ingat, perubahan bertahap adalah kunci kesuksesan.

Berikut adalah beberapa hal yang dapat Anda lakukan untuk mencapai konsistensi seiring berkembangnya code base Kotlin Anda:

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 lint Android dan alat analisis statis lainnya. klint, 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

Secara umum, Kotlin mendukung interoperabilitas dengan Java tanpa masalah, tetapi ingat hal berikut.

Nullability

Kotlin bergantung pada anotasi nullability pada kode yang dikompilasi untuk menyimpulkan nullability pada sistem Kotlin. Jika anotasi tidak disediakan, Kotlin akan didefaultkan ke jenis platform yang dapat dianggap sebagai jenis nullable atau non-nullable. Namun, hal ini dapat menyebabkan masalah NullPointerException waktu proses, jika tidak ditangani dengan cermat.

Mengadopsi 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.

Ini merupakan jebakan yang sangat umum yang dihadapi oleh developer Kotlin baru. Asumsikan kode Kotlin berikut:

val nullableFoo: 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 sederhana dan smart cast, seperti yang ditunjukkan pada 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

Class dan fungsinya ditutup untuk ekstensi secara default di Kotlin. Anda harus secara eksplisit membuka class dan fungsi yang ingin Anda jadikan subclass. Perilaku ini adalah keputusan desain bahasa yang dipilih untuk mempromosikan komposisi daripada turunan. Kotlin memiliki dukungan bawaan untuk menerapkan perilaku melalui delegasi guna membantu menyederhanakan komposisi.

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 dari Mockito, yang memungkinkan Anda meniru class dan metode akhir. Atau, Anda dapat menggunakan Semua plugin compiler terbuka 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: