ใช้ Kotlin สำหรับทีมขนาดใหญ่

การย้ายไปใช้ภาษาใหม่ๆ อาจเป็นเรื่องที่น่ากังวล เคล็ดลับสู่ความสำเร็จคือการเริ่มต้นอย่างช้าๆ ย้ายข้อมูลเป็นส่วนๆ และทดสอบบ่อยๆ เพื่อให้ทีมพร้อมรับความสำเร็จ Kotlin ช่วยให้การย้ายข้อมูลเป็นเรื่องง่าย เนื่องจากคอมไพล์เป็น JVM Bytecode และทำงานร่วมกับ Java ได้อย่างสมบูรณ์

การสร้างทีม

ขั้นตอนแรกก่อนย้ายข้อมูลคือการสร้างความเข้าใจพื้นฐานร่วมกันสำหรับทีม เคล็ดลับต่อไปนี้อาจเป็นประโยชน์ในการเร่งการเรียนรู้ของทีม

จัดตั้งกลุ่มศึกษา

กลุ่มศึกษาเป็นวิธีที่มีประสิทธิภาพในการส่งเสริมการเรียนรู้และการจดจำ การศึกษาชี้ให้เห็น ว่าการท่องสิ่งที่ได้เรียนรู้ในสภาพแวดล้อมแบบกลุ่มช่วย เสริมเนื้อหา ซื้อหนังสือ Kotlin หรือสื่อการเรียนรู้อื่นๆ ให้สมาชิกแต่ละคนในกลุ่ม และขอให้กลุ่มอ่านหนังสือ 2-3 บทต่อสัปดาห์ ในแต่ละครั้งที่พบกัน กลุ่มควรเปรียบเทียบสิ่งที่ได้เรียนรู้และพูดคุยเกี่ยวกับคำถามหรือข้อสังเกตต่างๆ

สร้างวัฒนธรรมการสอน

แม้ว่าไม่ใช่ทุกคนจะคิดว่าตัวเองเป็นครู แต่ทุกคนก็สามารถสอนได้ ตั้งแต่หัวหน้าทีมหรือหัวหน้าฝ่ายเทคโนโลยีไปจนถึงผู้ร่วมงานแต่ละคน ทุกคนสามารถส่งเสริมสภาพแวดล้อมการเรียนรู้ที่จะช่วยให้มั่นใจได้ถึงความสำเร็จ วิธีหนึ่งในการดำเนินการนี้คือการจัดงานนำเสนอเป็นระยะๆ โดยกำหนดให้คนในทีม 1 คนพูดถึงสิ่งที่ได้เรียนรู้หรือต้องการแชร์ คุณสามารถใช้ประโยชน์จากกลุ่มศึกษาโดยขออาสาสมัครนำเสนอบทใหม่ทุกสัปดาห์จนกว่าทีมจะรู้สึกสบายใจกับภาษา

กำหนดแชมเปี้ยน

สุดท้าย ให้กำหนดแชมเปี้ยนเพื่อเป็นผู้นำความพยายามในการเรียนรู้ บุคคลนี้สามารถทำหน้าที่เป็น ผู้เชี่ยวชาญเฉพาะเรื่อง (SME) เมื่อคุณเริ่มกระบวนการนำไปใช้ คุณควรเชิญบุคคลนี้เข้าร่วมการประชุมฝึกซ้อมทั้งหมดที่เกี่ยวข้องกับ Kotlin บุคคลนี้ควรมีความกระตือรือร้นเกี่ยวกับ Kotlin อยู่แล้วและมีความรู้ในการทำงาน

ผสานรวมอย่างช้าๆ

การเริ่มต้นอย่างช้าๆ และคิดอย่างมีกลยุทธ์เกี่ยวกับส่วนใดของระบบนิเวศที่จะย้ายก่อนเป็นสิ่งสำคัญ โดยส่วนใหญ่มักจะดีที่สุดหากจำกัดการย้ายข้อมูลไว้ที่แอปเดียวภายในองค์กรแทนที่จะเป็นแอปหลัก ในส่วนของการย้ายข้อมูลแอปที่เลือกนั้น สถานการณ์ของแต่ละแอปจะแตกต่างกัน แต่ต่อไปนี้คือจุดเริ่มต้นทั่วไปบางส่วน

โมเดลข้อมูล

โมเดลข้อมูลของคุณน่าจะประกอบด้วยข้อมูลสถานะจำนวนมากพร้อมกับเมธอด 2-3 รายการ นอกจากนี้ โมเดลข้อมูลอาจมีเมธอดทั่วไป เช่น 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 ที่มีเมธอด 2-3 รายการดังนี้

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 ช่วยให้คุณมีอินเทอร์เฟซ Utils เดียวกันสำหรับผู้เรียก Java ในขณะเดียวกันก็มี 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
}

สุดท้าย ให้เพิ่ม Annotation 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 แล้วและคุณได้ย้ายข้อมูลส่วนเล็กๆ แล้ว คุณสามารถย้ายไปจัดการกับคอมโพเนนต์ขนาดใหญ่ขึ้น เช่น Fragment, Activity, ออบเจ็กต์ ViewModel และคลาสอื่นๆ ที่เกี่ยวข้องกับตรรกะทางธุรกิจ

ข้อควรพิจารณา

Kotlin มีรูปแบบเฉพาะของตัวเองที่ช่วยให้กระชับเช่นเดียวกับ Java อย่างไรก็ตาม ในตอนแรกคุณอาจพบว่าโค้ด Kotlin ที่ทีมสร้างขึ้นมีลักษณะคล้ายกับโค้ด Java ที่จะนำมาแทนที่ ซึ่งจะเปลี่ยนแปลงไปเมื่อทีมมีประสบการณ์การใช้ Kotlin มากขึ้น อย่าลืมว่าการเปลี่ยนแปลงทีละน้อยคือกุญแจสู่ความสำเร็จ

ต่อไปนี้คือสิ่งที่คุณทำได้เพื่อให้โค้ด Kotlin มีความสอดคล้องกันมากขึ้นเมื่อฐานของโค้ดเติบโตขึ้น

มาตรฐานการเขียนโค้ดทั่วไป

อย่าลืมกำหนดชุดรูปแบบการเขียนโค้ดมาตรฐานตั้งแต่เนิ่นๆ ในกระบวนการนำไปใช้ คุณสามารถเบี่ยงเบนจากคู่มือแนะนำเกี่ยวกับ Kotlin ของ Android ได้หากเหมาะสม

เครื่องมือวิเคราะห์แบบคงที่

บังคับใช้มาตรฐานการเขียนโค้ดที่กำหนดไว้สำหรับทีมโดยใช้ Android Lint และเครื่องมือวิเคราะห์แบบคงที่อื่นๆ klint ซึ่งเป็น Linter ของ Kotlin จากบุคคลที่สามยังมีกฎเพิ่มเติมสำหรับ Kotlin ด้วย

การรวมอย่างต่อเนื่อง

ตรวจสอบว่าคุณปฏิบัติตามมาตรฐานการเขียนโค้ดทั่วไปและมีการทดสอบโค้ด Kotlin อย่างเพียงพอ การทำให้การทดสอบเป็นส่วนหนึ่งของกระบวนการสร้างอัตโนมัติจะช่วยให้มั่นใจได้ถึงความสอดคล้องและการปฏิบัติตามมาตรฐานเหล่านี้

ความสามารถในการทำงานร่วมกัน

Kotlin ทำงานร่วมกับ Java ได้อย่างราบรื่นในกรณีส่วนใหญ่ แต่โปรดทราบสิ่งต่อไปนี้

ความสามารถในการเว้นว่าง

Kotlin อาศัย Annotation ความสามารถในการเว้นว่างในโค้ดที่คอมไพล์แล้วเพื่ออนุมานความสามารถในการเว้นว่างในฝั่ง Kotlin หากไม่มี Annotation Kotlin จะใช้ประเภทแพลตฟอร์มเป็นค่าเริ่มต้น ซึ่งสามารถถือเป็นประเภทที่เว้นว่างได้หรือเว้นว่างไม่ได้ อย่างไรก็ตาม การดำเนินการนี้อาจทำให้เกิดปัญหา NullPointerException ขณะรันไทม์ได้หากไม่ระมัดระวัง

นำฟีเจอร์ใหม่ไปใช้

Kotlin มีไลบรารีใหม่ๆ และไวยากรณ์ที่กระชับมากมายเพื่อลดโค้ดซ้ำ ซึ่งช่วยเพิ่มความเร็วในการพัฒนา อย่างไรก็ตาม โปรดระมัดระวังและเป็นระบบเมื่อใช้ฟังก์ชันไลบรารีมาตรฐานของ Kotlin เช่น ฟังก์ชันคอลเล็กชัน, Coroutine และ Lambda

ต่อไปนี้คือข้อผิดพลาดที่พบบ่อยมากที่นักพัฒนาแอป 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 ได้ที่ลิงก์ต่อไปนี้