מקרים לדוגמה

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

משך הקריאה: 11 דקות
לצפייה בפרופיל של פבלו סטביצקי הצגת הפרופיל של רבקה פרנקס
Pavlo Stavytskyi וכן Rebecca Franks

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

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

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

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

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

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

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

Product Design 1.png

כשמעבירים בסיס קוד בגודל כזה לפיתוח נייטיב, קל להתפתות לבחור בדרך הקלה ולהטמיע רכיבים של ממשק משתמש של פיתוח נייטיב בתוך היררכיית התצוגות הקיימת. כשלב הדרגתי במהלך העברה הדרגתית, זה תקין לחלוטין. עם זאת, בטווח הארוך, שילוב של פיתוח נייטיב בבסיס קוד מבוסס-תצוגה הוא מאתגר. כלי 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 נקרא בקוד אימפרטיבי ואז נלכד בתוך פונקציית למבדה של 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 נמצא ב-constructor, כך שאין לו גישה לחברים או למצב של המחלקה, והמקור היחיד שלו לארגומנטים הוא ה-constructor. כך היא שוות ערך לפונקציית @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")
      }
    }
    
    ...
  },
)

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

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

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

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

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

Quote-Pavlo-New.jpg

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Diagram 1.png

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

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

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

Diagram 2.png

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

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

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

קומפוזיציה שניתן להשהות (מופעלת כברירת מחדל ב-Compose 1.10) מאפשרת ליצור פריטים יקרים של רשימה עם טעינה מדורגת באופן מצטבר על פני פריימים כדי למנוע קפיצות. כשמשלבים את זה עם LazyLayoutCacheWindow (נוסף ב-Compose 1.9), השילוב משפר משמעותית את החלקות של הגלילה.בבדיקות פנימיות שבוצעו לאחרונה ב-מטא, שילוב של קומפוזיציה שניתן להשהות עם 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 שומר חצי מסך מורכב מראש, כך שהכמות המוחלטת משתנה בהתאם לגובה המסך ותומכת בגורמי צורה שונים: יותר בטאבלט או במכשיר מתקפל פתוח, פחות בטלפון קומפקטי. 

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

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


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

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

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

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

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

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

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

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

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

כותב/ת המסמך:
להמשך קריאה