Case Studies

איך מהנדסי Instagram Direct בנו ארכיטקטורת ממשק משתמש מבוססת-AI באמצעות Jetpack Compose וצמצמו את עלות האסימונים לכל סשן של סוכן ב-33%

משך הקריאה: 11 דקות

הפוסט הזה בבלוג נכתב בשיתוף פעולה עם צוות Meta

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

המעבר ל-Jetpack Compose ב-Instagram Direct היה מעבר מורכב יותר מחידוש רגיל של ממשק משתמש. הצוות יצר בסיס קוד של ממשק משתמש מבוסס-AI שהוא קטן ב-50% מההטמעה המקורית, ובו בזמן קיצר ב-35% את זמן הביצוע של סוכן ה-AI, הפחית ב-32% את מספר האינטראקציות בין מהנדסים לסוכן, והפחית ב-33% את עלות האסימונים. בשיתוף פעולה הדוק עם Google, הצוות אימץ את Jetpack Compose תוך שמירה על רף ביצועים גבוה. באמצעות האופטימיזציות של הביצועים, מטא ו-Google שיפרו את Compose לא רק עבור Instagram, אלא גם עבור המערכת האקולוגית הרחבה יותר של מפתחי Android.

מודרניזציה של בסיס הקוד בהיקף עצום

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

צוות Instagram Direct בחר ב-Jetpack Compose כרכיב מרכזי לבניית ארכיטקטורת ממשק משתמש מבוססת-AI. האופי הדקלרטיבי שלו מבטיח שהקוד יהיה תמציתי, צפוי וקל יותר למודלים של AI להבנה מבחינה מבנית, עם פחות תופעות לוואי, פחות מצב משתמע וגבולות ברורים יותר בין רכיבים.

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

Product Design 1.png

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

בניית ארכיטקטורת ממשק משתמש מבוססת-AI

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

דוגמה 1

class ChatItem(
  val features: FeatureFlagProvider
) : RecyclerViewItem<ComposeViewHolder, ChatUiState> {

  // Imperative context:
  // AI could often take the path of least resistance and generate a mutable
  // state here, dispatched outside the ChatUiState. This class survives
  // re-bindings and is shared across multiple items, ultimately leading to
  // unexpected, hard-to-reproduce bugs.
  var isPinned: Boolean = false

  override fun onBind(holder: ComposeViewHolder, uiState: ChatUiState) {
      // Imperative context
      val isPinnedChatsEnabled = features.isEnabled("pinned_chats_feature")

      // Declarative context
      holder.composeView.setContent {

        // Blending imperative and declarative contexts
        if (isPinnedChatsEnabled) {
          Button(onClick = { isPinned = !isPinned }) {
            Text(if (isPinned) "Unpin" else "Pin")
          }
        }
        
        ...
      }
  }
}


בקטע הקוד שלמעלה, יש שתי בעיות. קודם, הדגל isPinnedChatsEnabled נקרא בקוד אימפרטיבי ואז נלכד בתוך lambda של Compose, צימוד עדין בין פרדיגמות. שנית, isPinned נמצא כשדה שניתן לשינוי בפריט עצמו ולא ב-ChatUiState, ולכן הוא שורד RecyclerView קישור מחדש ושימוש חוזר בשורות, וגורם לדליפות ולבאגים שקשה לשחזר.

גם כשמנקים את הקוד על ידי הקצאת פונקציה ייעודית @Composable לפריט, הבעיות נשארות זהות.

דוגמה 2

class ChatItem(
  val features: FeatureFlagProvider
) : ComposeRecyclerViewItem<ChatUiState> {

  // Imperative context
  val isPinnedChatsEnabled = features.isEnabled("pinned_chats_feature")
  var isPinned: Boolean = false

  // Declarative context
  @Composable
  override fun Content(uiState: ChatUiState) {

 
    // Blending imperative and declarative contexts
    if (isPinnedChatsEnabled) {
      Button(onClick = { isPinned = !isPinned }) {
        Text(if (isPinned) "Unpin" else "Pin")
      }
    }

    ...
  }
}

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

כדי שה-AI יוכל לעבוד עם בסיס הקוד, הוא צריך לעמוד בשני כללים מעשיים: 

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

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

דוגמה 3

class ChatItem(
  val features: FeatureFlagProvider,
  val onPin: (Boolean) -> Unit,
) : ComposeItem<ChatUiState>(

 
   // Compose UI
   content = { uiState: ChatUiState ->
    val isPinnedChatsEnabled = features.isEnabled("pinned_chats_feature")

    if (isPinnedChatsEnabled) {
      Button(onClick = { onPin(!uiState.isPinned) }) {
        Text(if (uiState.isPinned) "Unpin" else "Pin")
      }
    }
    
    ...
  },
)

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

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

  • לכתוב את כל קוד ה-Compose באמצעות AI.
  • המשכנו לשפר את הממשק, טיפלנו במקרים חריגים וצמצמנו פערים בביצועים, עד שהממשק הושק למשתמשים אמיתיים בבדיקה ציבורית.

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

תוצאות ההעברה אישרו את הגישה. בממשקי Instagram Direct שהועברו, Jetpack פיתוח נייטיב אפשר לצוות לצמצם את הכמות הכוללת של קוד ממשק המשתמש ב-50%. ככל שיש פחות קוד ש-AI צריך ליצור, כך הפלט איכותי יותר ועלות הטוקנים לכל משימה נמוכה יותר. 

Quote-Pavlo-New.jpg

ניתוח נתונים פנימי של בסיס הקוד של Android עבור Instagram Direct השווה בין סשנים של סוכני AI שעובדים על ממשק משתמש של Compose לבין אותן משימות באמצעות Android Views. השיפורים ביעילות היו ברורים בשני מאפיינים:

  • לכל תו בקוד שהתקבל: כתיבת קוד עם 32% פחות אינטראקציות בין מהנדס לסוכן ועם 35% פחות זמן ביצוע של הסוכן (הזמן שחל מרגע שהסוכן מתחיל לעבוד על בקשה של מהנדס ועד שהוא מחזיר תשובה).
  • לכל סשן של נציג: העלות הכוללת של הטוקנים ירדה ב-33% עם התכונה 'יצירת תשובות' בהשוואה לתכונה 'תצוגות'.

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

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

כשציון הסיכון המצטבר של קובץ מוכפל, ממשק המשתמש שהוטמע באמצעות Android Views מפחית את יעילות משאבי הסוכן ב-30% (לכל תו שהוזן). באותן נסיבות, ההפחתה באמצעות ממשק המשתמש של Jetpack Compose היא רק 9%

במסגרת שותפות בין Google לבין Meta, צוות Instagram Direct הביא פרספקטיבה חדשה לאימוץ Compose – הוא ניגש לנושא דרך עדשת ההתאמה של בסיס הקוד ל-AI, ולא רק ככתיבה מחדש של ממשק המשתמש. העבודה הזו חשפה את היתרון של Compose כבסיס לבניית בסיסי קוד וארכיטקטורות שמתבססים על AI, במיוחד כשמיישמים אותו בקנה מידה של אפליקציות כמו אינסטגרם.

אופטימיזציה של הביצועים 

‫Instagram Direct הוא אחד מהאזורים המרכזיים באפליקציה, והמשתמשים מצפים שהוא יהיה מהיר ורספונסיבי בכל רגע. השימוש ב-Jetpack Compose דרש שכתוב משמעותי של ממשק המשתמש, והמטרה העיקרית הייתה לשמור על חוויית משתמש באיכות גבוהה בלי לפגוע בביצועים.

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

ב-Instagram נמדדים מאות, ואפילו אלפי מדדי ביצועים. בנוגע לאימוץ של Compose, שלושת הנושאים הבאים היו החשובים ביותר:

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

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

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

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

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

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

Diagram 1.png

המשימה העיקרית של הצוות הייתה העברה הדרגתית של כמה מאות פריטים בודדים ברשימה אל Compose במסגרת הארכיטקטורה הקיימת שמבוססת על RecyclerView, והשקתם בסביבת הייצור בקבוצות קטנות ועצמאיות במסגרת בדיקות A/B – כל זאת בלי שינויים גלויים בחוויית העברת ההודעות של המשתמש.

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

כלומר, רכיבי Compose UI צריכים להיות מופשטים מהמסגרת שבה הם כלולים, ועדיין להיות תואמים ל-RecyclerView ול-LazyColumn בו-זמנית. חשוב לא פחות להחליף בין השניים בזמן הריצה באמצעות דגלי תכונות, כדי להפעיל בדיקות A/B.

Diagram 2.png

הפריטים החדשים של כתיבת מוזיקה תואמים באופן טבעי ל-LazyColumn ואפשר להוסיף אותם לעץ של יצירה רציפה, אבל נוצר גם API של פעולות הדדיות כדי להוסיף אותם גם ל-RecyclerView. כך יכולנו להשיק את ההגדרה של LazyColumn במסגרת בדיקת A/B לצד RecyclerView – תוך שימוש חוזר באותם פריטים של Compose ושיפור הביצועים, בלי לשבש את העבודה של שאר הצוות בפיתוח ובשיפור התכונות.

הגודל, המורכבות והרגישות של אינסטגרם אפילו לשינויים הקטנים ביותר היוו אתגר ייחודי ל-Jetpack Compose. כדי לטפל בבעיות האלה נדרשה שותפות מעשית ואיטרטיבית. מהנדסים של Google ומטא עבדו בשיתוף פעולה הדוק כדי לנתח מדדים, לזהות את נקודות החולשה ולתכנן יכולות חדשות של כתיבת קוד שיעזרו להשיג ביצועים טובים יותר מהביצועים של המתחרים. כתוצאה מהשותפות הזו, יש כמה תוספות חשובות ל-Jetpack Compose: קומפוזיציה שאפשר להשהות עם LazyLayoutCacheWindows ומעקב אחר חשיפה. 

קומפוזיציה שאפשר להשהות באמצעות LazyLayoutCacheWindows

קומפוזיציה שאפשר להשהות (מופעלת כברירת מחדל ב-Compose 1.10) מאפשרת ליצור פריטים יקרים של רשימה עצלה באופן מצטבר על פני פריימים כדי למנוע בעיות בממשק (jank). בשילוב עם LazyLayoutCacheWindow (נוסף ב- Compose 1.9), השילוב משפר באופן משמעותי את החלקות של הגלילה. בבדיקות פנימיות שבוצעו לאחרונה ב-Meta, שילוב של יצירה עם אפשרות להשהיה עם אזור תצוגה אחד LazyLayoutCacheWindow הפחית את מספר הנטישות הגדולות של פריימים לדקה (LFDs/m) בכ-13% בהשוואה ל-Compose רגיל. השימוש ב-Cache Window בלבד הפחית את העלות בכ-8% בהשוואה לאותו בסיס. LFDs/m הוא מדד פנימי שבו Meta משתמשת כדי לעקוב אחרי גמגומים בולטים בזמן גלילה.

Quote-Fabio.jpg


שימוש ב-LazyLayoutCacheWindow באפליקציה מכין ושומר פריטים מחוץ למסך בתוך פס מבוסס-פיקסלים מסביב לאזור התצוגה, כדי לאפשר גלילה מהירה. כדי להשתמש ב-LazyLayoutCacheWindows באפליקציה, אפשר להשתמש בגרסה האחרונה של Compose‏ 1.13.0-alpha03 ולהגדיר אותה כמו בדוגמה הבאה:

val cacheWindow = LazyLayoutCacheWindow(ahead = 150.dp, behind = 100.dp)
// OR
val cacheWindow = LazyLayoutCacheWindow(aheadFraction = 0.5f, behindFraction = 0.3f)

LazyColumn(state = state, cacheWindow = cacheWindow) {
    ...
}

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

  • ‫Dp: אורך מוחלט קבוע. ahead = 150.dp שומר 150dp של תוכן שנוצר מעבר לקצה הגלוי, ללא קשר למכשיר.
  • Float: שבר של אזור התצוגה. ‫aheadFraction = 0.5f שומר חצי מסך מורכב מראש, כך שהכמות המוחלטת משתנה בהתאם לגובה המסך ותומכת בגורמי צורה שונים: יותר בטאבלט או בטלפון מתקפל פתוח, פחות בטלפון קומפקטי. 

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

רישום חשיפות באמצעות onVisibilityChanged

‫
API‏  onVisibilityChanged (נוסף ב-Compose 1.9.0) היה תוצאה חשובה נוספת של השותפות הטכנית בין Google ל-מטא. הוא מספק דרך עקבית למשטחים גדולים של Jetpack Compose לדעת מתי רכיב קומפוזבילי גלוי בפועל על המסך, ומחליף הטמעות מותאמות אישית שנעשה בהן שימוש בעבר. רק ב-Instagram Direct, אותות החשיפה האלה משמשים במאות קבצים כדי לתמוך במדדי איכות המוצר שתלויים בשאלה אם רכיבי ממשק המשתמש הוצגו לאנשים בפועל.

ביצועי ההפעלה

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

הביצועים של ממשק המשתמש של Compose בהפעלה בתוך Instagram Direct עברו אופטימיזציה באמצעות פרופילים של Baseline, שמבצעים קומפילציה מראש של נתיבי קוד פעילים בזמן ההתקנה, כך ש-Compose מבצע רינדור מהיר כבר מההפעלה הראשונה.

לקחים מהמעבר של Instagram Direct ל-Jetpack Compose 

  • ההחזר על ההשקעה ב-Jetpack Compose הוא מיידי: לא צריך להשתמש בתהליכי עבודה מתקדמים של AI כדי ליהנות מ-Compose. הקיצור של כ-50% בקוד אומר שיש פחות קוד לתחזוקה, ופחות שטח פנים לבאגים.
  • תכנון ארכיטקטורה מבוססת-AI הוביל לשיפורים משמעותיים, כולל קיצור של 35% בזמן הביצוע של סוכן ה-AI, צמצום של 32% במספר האינטראקציות בין מהנדס לסוכן וחיסכון של 33% בעלות האסימונים.
  • למרות שיש הרבה ממשקי API של יכולת פעולה הדדית ותמיכה בשילוב של Views ופיתוח נייטיב, מומלץ להעביר משטחים גדולים יותר ולא רכיבים קטנים בנפרד. כך ממשק המשתמש נשאר בהיררכיית קומפוזיציה אחת ללא הפרעות, וכל האופטימיזציות המובנות של Compose לשיפור הביצועים זמינות.
  • שילוב של Pausable composition עם LazyLayoutCacheWindow: שילוב של שתי האפשרויות האלה מניב תוצאות טובות יותר מאשר שימוש רק בחלונות מטמון. אם משתמשים רק בחלון המטמון, פריט כבד עדיין יכול לנסות להרכיב את עצמו במעבר יחיד, ועלול לחרוג מהתקציב של המסגרת.
  • להוספת תוכן ל-Compose ‫Meta שיתפה פעולה עם צוות Jetpack Compose כדי להפוך את המשוב והרעיונות שלהם למציאות ב-Compose. העבודה על ערכת כלים בקוד פתוח מאפשרת לכולנו ליהנות מתיקוני באגים ושיפורים בביצועים שמתבצעים באופן מרכזי. לכן, חשוב לשתף את המשוב שלכם.

המעבר ל-Jetpack פיתוח נייטיב הביא לשיפורים משמעותיים בפיתוח בעזרת AI, ופישט את הנדסת ממשק המשתמש ב-Instagram. הגישה הדקלרטיבית מצמצמת את הקוד הסטנדרטי, מקלה על הבנת המצב ומשפרת את הפרודוקטיביות הכוללת של המפתחים. צוות ההנדסה של אינסטגרם מצפה להטמיע את Compose בעוד פלטפורמות באפליקציה, ולהמשיך בשיתוף הפעולה בין Google ל-Meta כדי להביא שיפורים נוספים למשתמשי אינסטגרם ולמשתמשי Jetpack Compose. 

אם עוד לא ניסיתם את Compose, עכשיו עם עזרה מ-AI, קל יותר מתמיד לעבור אל Jetpack Compose.

תודות. תודה למיכל ז'ילינסקי ולמתיו דו מ-Meta, ולאנדריי שיקוב ולג'ורג' מאונט מ-Google, על העבודה שלהם לשיפור הביצועים של Compose באמצעות שיתוף הפעולה בין Meta ל-Google. תודה גם לגארי יה (Gary Ye) מ-Meta על העזרה בהוספת התכונה 'יצירת פוסט' ל-Instagram Direct, ולגופאל ג'ונג'ה (Gopal Juneja) מ-Meta על התמיכה במאמץ הזה באמצעות מדעי הנתונים!

נכתב על ידי:
להמשך קריאה