שימוש ב-Kotlin לצוותים גדולים

המעבר לשפה חדשה יכול להיות משימה מרתיעה. המתכון להצלחה הוא להתחיל לאט, לעבור מקטעים ולבדוק לעיתים קרובות כדי להתאים את הצוות להצלחה. Kotlin מקל על המעבר, כי הוא עובר לבייטקוד (bytecode) של JVM יכולה לפעול באופן הדדי עם Java.

בניית הצוות

השלב הראשון לפני המעבר הוא ליצור הבנה בסיסית משותפת עבור של הצוות. ריכזנו כמה טיפים שיוכלו לעזור לכם להאיץ הלמידה של הצוות.

יצירת קבוצות לימוד

קבוצות למידה הן דרך יעילה לסייע ללמידה ולשימור. מחקרים מציעים שדקלום את מה שלמדתם בסביבה קבוצתית עוזר לחזק את החומר. לקבלת ספר קוטלין או אחר חומר לימוד לכל אחד מחברי הקבוצה ולבקש מהחברים בקבוצה לעבור על כמה פרקים בכל שבוע. במהלך כל פגישה, כל המשתתפים צריכים להשוות ביניהם הם למדו ולדון בשאלות או בתצפיות.

בונים תרבות של הוראה

לא כולם מחשיבים את עצמם כמורים, אבל כולם יכולים ללמד. כל אחד, כמו טכנולוגיה או צוות, יכול להיות תורם תוכן ספציפי מעודדים סביבת לימודים שיכולה להבטיח הצלחה. אחת הדרכים היא מאפשרת לקיים מצגות תקופתיות שבהן אחד מחברי הצוות מיועד לדבר על משהו שהוא למד או שהוא רוצה לשתף. אפשר למנף את קבוצת הלמידה ולבקש ממתנדבים להציג פרק חדש בכל פעם עד שתגיעו לנקודה שבה הצוות שלכם ירגיש בנוח בשפת היעד.

בחירת גיבור

לבסוף, לימדו את הגיבור להוביל מאמץ למידה. המשתמש הזה יכול לפעול בתור מומחה לנושא מסוים (SME) כשתתחילו את תהליך ההטמעה. זה כן חשוב לכלול את האדם הזה בכל פגישות התרגול שקשורות לנושא Kotlin. במצב אידיאלי, לאדם הזה כבר יש תשוקה רבה ל-Kotlin ידע בעבודה.

שילוב איטי

כדאי להתחיל לאט ולחשוב בצורה אסטרטגית על החלקים בסביבה העסקית קודם כל, צריך לזוז. בדרך כלל מומלץ לבודד את המידע הזה לאפליקציה אחת בתוך ארגון ולא אפליקציית דגל. כשמדובר בהעברת האפליקציה שנבחרה, כל אחד מהמצבים שונה, אבל הנה כמה מקומות נפוצים שכדאי להתחיל בהם.

מודל נתונים

מודל הנתונים מורכב ככל הנראה מהרבה פרטים לגבי מצב המערכת, שיטות. למודל הנתונים עשויות להיות גם שיטות נפוצות כמו 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 וכן הלאה) אפשר לייצג פונקציות התוסף של Kootlin ומשמש את ה-codebase הקיים שלכם ב-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, ניתן לספק את אותו ממשק של 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
}

לסיום, מוסיפים הערת 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 = ...
val fooString = myString.foo()
...

Java

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

סיום ההעברה

אחרי שהצוות שלכם יסכים להשתמש ב-Kotlin והעברתם אזורים קטנים יותר, אפשר לעבור להתמודדות עם רכיבים גדולים יותר כמו מקטעים, פעילויות, אובייקטים מסוג ViewModel ומחלקות אחרות שקשורות ללוגיקה עסקית.

שיקולים

בדומה ל-Java יש סגנון ספציפי, ל-Kotlin יש סגנון אידיומטי משלה נוסף לתמציתיות שלו. עם זאת, ייתכן שתגלו בהתחלה קוד Kotlin שהצוות שלך מפיק נראה יותר כמו קוד Java שהוא מחליף. המצב הזה משתנה עם הזמן, ככל שחוויית השימוש של הצוות שלכם ב-Kotlin גדלה. זכרו, הדרגתיות שינוי הוא המפתח להצלחה.

כמה דברים שאפשר לעשות כדי לשמור על עקביות בתור בסיס הקוד של Kotlin גדל:

סטנדרטים נפוצים בתכנות

חשוב להגדיר קבוצה סטנדרטית של מוסכמות תכנות כבר בשלב מוקדם. תהליך האימות. אפשר להתרחק מ-Android מדריך סגנון קוטלין במקומות המתאימים.

כלים לניתוח סטטי

לאכוף את תקני התכנות שהוגדרו לצוות שלכם באמצעות Android lint וכלי ניתוח סטטיים אחרים. klint, חברת Kotlin של צד שלישי linter, מספק גם כללים נוספים עבור Kotlin.

אינטגרציה רציפה (CI)

חשוב לעמוד בסטנדרטים נפוצים של תכנות ולספק בדיקות מספקות עבור קוד Kotlin. להפוך את החלק הזה לתהליך build אוטומטי כדי להבטיח עקביות וציות לסטנדרטים האלה.

יכולת פעולה הדדית

בדרך כלל, Kotlin עובדת עם Java בצורה חלקה, אבל חשוב לזכור במעקב.

ערך אפס

Kotlin מסתמך על הערות null בקוד שעבר הידור כדי להסיק שיכול להיות null בצד של קוטלין. אם לא יסופקו הערות, Kotlin ישתמש בברירת המחדל של סוג פלטפורמה שיכול להיחשב כ-null או כסוג שאינו null. הזה עם זאת, אם לא יטופלו, יכולות להוביל לבעיות מסוג NullPointerException בסביבת זמן הריצה בזהירות.

שימוש בתכונות חדשות

Kotlin מספקת הרבה ספריות חדשות תחבירי וסוכר תחבירי כדי להפחית את פליטת הבוילר, מה שעוזר להגביר את ההתפתחות המהירות שלו. עם זאת, חשוב לנהוג בזהירות ובשיטתיות כשמשתמשים בתקן Kotlin בפונקציות לספרייה, פונקציות איסוף, coroutines, ו-lambdas.

הנה מלכודת נפוצה מאוד שמפתחי Kotlin חדשים נתקלים בה. מניחים בקוד Kotlin:

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

הכוונה בדוגמה הזו היא להפעיל את 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, מסתמכים על הטמעה של ממשק או ירושה כדי לבטל התנהגויות בדיקה. עבור בדיקות יחידה, אפשר להפעיל את השימוש Inline Maker של Mockito, שמאפשר לדמות שיטות וסיווגים סופיים. לחלופין, אפשר להשתמש פלאגין מהדר (compiler) מסוג All-Open כדי לפתוח כל כיתת Kotlin ואת החברים בה שרוצים לבדוק, תהליך הידור (compilation). היתרון העיקרי של השימוש בפלאגין הזה הוא שהוא פועל גם בבדיקות יחידה וגם בבדיקות אינסטרומנטליות.

מידע נוסף

מידע נוסף על השימוש ב-Kotlin זמין בקישורים הבאים: