Sử dụng Kotlin cho các nhóm lớn

Việc di chuyển sang ngôn ngữ mới có thể là một nhiệm vụ khó khăn. Công thức để đạt được thành công là bắt đầu từ từ, di chuyển từng phần và thử nghiệm thường xuyên để giúp nhóm của bạn đạt được thành công. Kotlin giúp quá trình di chuyển trở nên dễ dàng vì ngôn ngữ này biên dịch mã nguồn thành mã byte JVM và hoàn toàn tương thích với Java.

Xây dựng nhóm

Bước đầu tiên trước khi di chuyển là xây dựng kiến thức chung cơ bản cho nhóm của bạn. Sau đây là một số mẹo có thể giúp bạn đẩy nhanh tốc độ học tập của nhóm mình.

Thành lập nhóm học tập

Nhóm học tập là một cách hiệu quả để thúc đẩy việc học và khả năng tiếp thu. Các nghiên cứu cho thấy việc nhắc lại những điều đã học trong một nhóm sẽ giúp ghi nhớ nội dung tốt hơn. Hãy tìm sách về Kotlin hoặc tài liệu học tập khác cho từng thành viên trong nhóm và yêu cầu nhóm đọc một vài chương mỗi tuần. Trong mỗi cuộc gặp, nhóm nên so sánh nội dung đã học và thảo luận về những thắc mắc hoặc nhận định của mình.

Xây dựng văn hoá dạy học

Mặc dù không phải ai cũng tự nhận mình là giáo viên, nhưng mọi người đều có thể dạy học. Từ trưởng nhóm hoặc kỹ sư trưởng đến cộng tác viên cá nhân, ai cũng có thể góp phần tạo ra môi trường học tập có thể giúp đảm bảo thành công. Một cách để thúc đẩy việc này là tổ chức các buổi thuyết trình định kỳ, trong đó một người trong nhóm được chỉ định để nói về những điều họ đã học hoặc muốn chia sẻ. Bạn có thể tận dụng nhóm học tập của mình bằng cách tìm người xung phong trình bày một chương mới mỗi tuần cho đến khi nhóm của bạn cảm thấy quen thuộc với ngôn ngữ này.

Chọn người dẫn dắt

Cuối cùng, hãy chọn ra người dẫn dắt một chiến dịch học tập. Người này có thể đóng vai trò là chuyên gia giải đáp vấn đề (SME) khi bạn bắt đầu quá trình áp dụng ngôn ngữ mới. Điều quan trọng là phải đưa người này vào tất cả các buổi thực hành liên quan đến Kotlin. Tốt nhất, đây nên là người vốn đã đam mê Kotlin và có kiến thức thực tiễn.

Tích hợp từ từ

Hãy bắt đầu từ từ và suy nghĩ một cách có chiến lược về những phần cần di chuyển đầu tiên trong hệ sinh thái của bạn. Tốt nhất là bạn nên di chuyển một ứng dụng đơn lẻ trong tổ chức thay vì một ứng dụng hàng đầu. Đối với việc di chuyển ứng dụng đã chọn, mỗi trường hợp đều khác nhau, nhưng dưới đây là một số điểm chung để bắt đầu.

Mô hình dữ liệu

Mô hình dữ liệu của bạn chắc hẳn sẽ bao gồm nhiều thông tin trạng thái cùng với một số phương thức. Mô hình dữ liệu cũng có thể có các phương thức phổ biến như toString(), equals()hashcode(). Các phương thức này thường có thể chuyển đổi và kiểm thử đơn vị một cách dễ dàng.

Chẳng hạn, giả sử bạn có đoạn mã Java sau đây:

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

Bạn có thể thay thế lớp trên Java bằng một dòng trên Kotlin, như minh hoạ bên dưới:

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

Sau đó, bạn có thể kiểm thử mã này theo bộ kiểm thử hiện tại. Tại đây, bạn nên bắt đầu từ từ bằng lần lượt từng mô hình và chuyển đổi những lớp chủ yếu là trạng thái mà không phải hành vi. Hãy nhớ kiểm thử thường xuyên trong suốt quá trình di chuyển.

Di chuyển mã kiểm thử

Một hướng khởi đầu khác mà bạn có thể xem xét là chuyển đổi các kiểm thử hiện tại và bắt đầu viết mã kiểm thử mới trong Kotlin. Cách này có thể giúp cho nhóm của bạn có thời gian để làm quen với ngôn ngữ trước khi viết mã nguồn mà bạn dự định cung cấp qua ứng dụng.

Di chuyển các phương thức tiện ích sang hàm mở rộng

Mọi lớp tiện ích tĩnh (StringUtils, IntegerUtils, DateUtils ,YourCustomTypeUtils, và v.v.) đều có thể được biểu thị thành hàm mở rộng của Kotlin và được sử dụng trong cơ sở mã nguồn Java hiện tại của bạn.

Ví dụ: hãy xem xét sử dụng lớp StringUtils qua một số phương thức:

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
   }

}

Sau đó, các phương thức này có thể được dùng ở nơi khác trong ứng dụng của bạn, như trong ví dụ sau:

...

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

...

Khi sử dụng các hàm mở rộng của Kotlin, bạn có thể cung cấp cùng một giao diện Utils cho phương thức Java, đồng thời cung cấp API ngắn gọn hơn cho cơ sở mã nguồn Kotlin mà bạn đang phát triển.

Để thực hiện việc này, bạn có thể bắt đầu bằng cách chuyển đổi lớp Utils này thành Kotlin bằng cách sử dụng lệnh chuyển đổi tự động do IDE cung cấp. Dữ liệu đầu ra có thể có dạng như trong ví dụ sau:

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
   }

}

Tiếp theo, hãy xoá định nghĩa lớp hoặc định nghĩa đối tượng, thêm tiền tố vào mỗi tên hàm bằng loại dữ liệu mà hàm này sẽ áp dụng, sau đó sử dụng thông tin này để tham chiếu loại trong hàm, như trong ví dụ sau:

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
}

Cuối cùng, hãy thêm chú thích JvmName vào đầu tệp nguồn để giúp tên đã biên dịch tương thích với phần còn lại của ứng dụng, như trong ví dụ sau:

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

Phiên bản cuối cùng sẽ có dạng như sau:

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

Xin lưu ý rằng hiện bạn có thể gọi các hàm này bằng cách sử dụng Java hoặc Kotlin thông qua các quy ước phù hợp với từng ngôn ngữ.

Kotlin

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

Java

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

Hoàn tất quá trình di chuyển

Khi nhóm của bạn đã thấy thoải mái với Kotlin và bạn đã di chuyển xong các phần nhỏ, thì bạn có thể chuyển sang giải quyết những thành phần lớn hơn, chẳng hạn như phân đoạn, hoạt động, đối tượng ViewModel và các lớp khác liên quan đến logic nghiệp vụ.

Những yếu tố nên cân nhắc

Giống như Java có một phong cách cụ thể, Kotlin cũng có phong cách riêng để giúp mã nguồn trở nên súc tích. Tuy nhiên, ban đầu bạn có thể thấy mã nguồn Kotlin mà nhóm của bạn tạo ra có vẻ giống với mã nguồn Java mà nhóm đang thay thế. Điều này sẽ thay đổi theo thời gian khi trải nghiệm của nhóm bạn với Kotlin phong phú hơn. Hãy nhớ rằng, thay đổi chậm rãi là chìa khoá để thành công.

Dưới đây là một vài việc bạn có thể làm để đạt được tính nhất quán khi phát triển cơ sở mã nguồn Kotlin:

Tiêu chuẩn lập trình phổ biến

Hãy nhớ xác định bộ quy ước lập trình ngay từ bước đầu của quá trình sử dụng. Bạn có thể làm khác hướng dẫn về quy tắc lập trình Android bằng Kotlin khi thích hợp.

Công cụ phân tích tĩnh

Thực thi các tiêu chuẩn lập trình đã đặt ra cho nhóm của bạn bằng cách sử dụng công cụ tìm lỗi mã nguồn Android và các công cụ phân tích tĩnh khác. klint, một công cụ tìm lỗi mã nguồn Kotlin của bên thứ ba, cũng cung cấp các quy tắc bổ sung cho Kotlin.

Tích hợp liên tục

Đảm bảo tuân thủ các tiêu chuẩn lập trình thông dụng và cung cấp đầy đủ phạm vi kiểm thử cho mã nguồn Kotlin. Khi đưa cách làm này vào quy trình xây dựng tự động, bạn có thể đảm bảo tính nhất quán và tuân thủ các tiêu chuẩn này.

Khả năng tương thích

Kotlin gần như tương tác liền mạch với Java, nhưng hãy lưu ý những điểm sau.

Tính chất rỗng

Kotlin dựa vào các chú giải tính chất rỗng trong mã đã biên dịch để suy ra tính chất rỗng ở phía Kotlin. Nếu không có chú giải, Kotlin sẽ mặc định sử dụng một loại nền tảng có thể được coi là loại có thể hoặc không thể nhận giá trị rỗng. Tuy nhiên, việc này có thể dẫn đến vấn đề về thời gian chạy NullPointerException nếu không được xử lý cẩn thận.

Áp dụng các tính năng mới

Kotlin cung cấp nhiều thư viện mới và cú pháp dễ hiểu để giảm lượng mã nguyên mẫu, giúp tăng tốc độ phát triển ứng dụng. Tuy nhiên, hãy thận trọng và bài bản khi sử dụng các hàm thư viện chuẩn của Kotlin, chẳng hạn như hàm tập hợp, coroutine, và hàm lambda.

Đây là một cái bẫy rất phổ biến mà các nhà phát triển Kotlin mới hay mắc phải. Giả sử bạn có mã nguồn Kotlin như sau:

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

Mục đích trong ví dụ này là thực thi foo.baz()foo.zap() nếu nullableFoo khác rỗng, qua đó tránh NullPointerException. Mặc dù mã này hoạt động như dự kiến, nhưng sẽ khó đọc hơn so với mã đơn giản để kiểm tra giá trị rỗng và truyền thông minh, như minh hoạ trong ví dụ sau đây:

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
}

Kiểm thử

Theo mặc định, các lớp và hàm của lớp sẽ bị đóng để mở rộng trong Kotlin. Bạn phải có mã rõ ràng để mở các lớp và hàm mà bạn muốn đưa vào lớp. Hành vi này là một quyết định có chủ đích khi thiết kế ngôn ngữ này, mục đích là để ưu tiên việc soạn mã mới thay vì dùng lại mã cũ. Kotlin đã tích hợp tính năng hỗ trợ triển khai hành vi thông qua tính năng uỷ quyền để giúp đơn giản hoá quá trình soạn mã.

Hành vi này sẽ gây ra vấn đề khi mô phỏng các khung tiêu chuẩn (như Mockito) nếu khung đó dựa trên việc triển khai giao diện hoặc kế thừa mã cũ để ghi đè các hành vi trong quá trình thử nghiệm. Đối với các kiểm thử đơn vị, bạn có thể cho phép sử dụng tính năng Mock Maker Line của Mockito để có thể mô phỏng các lớp và phương thức cuối cùng. Ngoài ra, bạn có thể sử dụng plugin biên dịch All-Open để mở lớp bất kỳ trong Kotlin và thành phần đi kèm mà bạn muốn kiểm thử trong quá trình biên dịch. Lợi thế chính của việc sử dụng plugin này là plugin hoạt động được với cả kiểm thử đơn vị và kiểm thử đo lường.

Thông tin khác

Để biết thêm thông tin về cách sử dụng Kotlin, hãy xem các đường liên kết sau: