תשתית לאפליקציות

העברת אפליקציית Google Play בת שני העשורים ל-Jetpack Compose

רמקולים

  • קיריל גרושניקוב

    מהנדס/ת תוכנה

  • ג'ון בוקנוגן (Jon Boekenoogen)

    מהנדס תוכנה

מידע כללי

מידע על ההרצאה

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

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

סיכום

  • במשך שש שנים, Google Play העבירה 97% מהחשיפות של המשתמשים למסכים שכוללים רק את Compose. בנוסף, ב-14 החודשים האחרונים חל שיפור של 30% בשיעור הקיטועים בדפים מרכזיים.
  • הטמעה הדרגתית מפחיתה את הסיכונים העסקיים בבסיסי קוד גדולים. הצוותים יכולים קודם להכיר את המערכת במסכים עם תנועה נמוכה, ואז להתקדם לאירוח של ComposeView ישירות ב-Activity root.
  • עיצוב דינמי פועל כולו בקוד באמצעות שכבות-על של MaterialTheme וספריית Material Color Utilities. כך אפשר למנוע פירוק של Activity, אבל יצירת ערכות צבעים בזמן ה-build עוזרת להגביל את זמן האחזור בזמן הריצה.
  • זרימת נתונים חד-כיוונית וממשק משתמש הצהרתי מפשטים את הארכיטקטורה ומסירים כמה סוגים של מרוצי תהליכים. הפעלת מקורות נתונים וטרנספורמציות של ממשק המשתמש במקביל שיפרה את זמן האחזור של הטעינה ב-Google Play בעשרות אלפיות השנייה.
  • בדיקות Lint אוטומטיות אוכפות את כללי האיכות של הקוד ואת כללי מערכת העיצוב. מערכת Play משתמשת בהם כדי לחסום צבעים בקידוד קשיח ולסמן בעיות פוטנציאליות בביצועים, כמו BoxWithConstraints.

Gemini Notebook

נושאים

  • jetpack-compose
  • מיגרציה
  • ביצועים
  • שיוך לנושאים
  • unidirectional-data-flow
  • lint-rules
  • developer-velocity

תמליל

הורדת התמליל

מבוא ואימוץ של חנות Google Play

  • שלום לכולם,

  • קוראים לי יונתן.

  • אני מצוות חנות Google Play.

  • זה הקולגה שלי, קיריל.

  • היום נדבר על איך העברנו הרבה קוד ממערכת View ו-Fragment ל-Compose.

  • בואו נתחיל.

  • אז איך התהליך הזה התנהל ומה היה ההיקף שלו?

  • בסיס הקוד של האפליקציה שלנו גדל באופן אורגני מאז 2007 בערך.

  • יש לנו כמה מיליוני שורות של קוד ייצור, 200 מסכים ו-500 רכיבים ייחודיים של ממשק משתמש שמשמשים בהרבה מהמסכים האלה.

  • בשנת 2020 החלטנו שמהירות הפיתוח, האמינות והביצועים לא עומדים ביעדים שהצבנו.

  • לכן החלטנו לאמץ סטאק תוכנות מודרני של ממשק משתמש.

  • בדקנו הרבה ספריות שונות.

  • היו לנו גם כמה חברים ב-AndroidX שדיברו איתנו על Compose באותו זמן, והחלטנו לאמץ את Compose ולהפוך לשותף הגדול הראשון של Compose.

  • איך היה?

  • שש שנים לאחר מכן, 97% מהחשיפות של המשתמשים באפליקציית חנות Play הן במסכים שנוצרו רק באמצעות Compose.

  • סליחה, כל הפיתוח לטלפונים ולמסכים גדולים עבר ל-Compose בלבד מאז 2020.

  • ואפילו גורמי הצורה המורחבים שלנו, XR,‏ TV,‏ Auto ו-Wear, עברו ל-Compose מאז 2025.

  • ו-Compose הוא גורם משמעותי מאוד בהצלחה הזו, וזו הסיבה שאנחנו ממשיכים להשתמש בו יותר ויותר.

  • הם השתמשו בחבילת מקרים לבדיקה מקיפה וחזקה מאוד שעזרה לנו לאמץ גרסאות חדשות של Compose פעמיים בשבוע.

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

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

  • זהו דף תוצאות החיפוש, דף הבית, דף הפרטים.

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

  • אז ראינו שיפור של 30% ב-14 החודשים האחרונים.

תוכנית העברה

  • אבל איך הגענו עד לכאן?

  • זה מה שאנחנו באמת רוצים לדבר עליו.

  • בואו נדבר על תוכנית ההעברה.

  • לכן, ב-Play נקטנו גישה רב-שלבית.

  • לא רצינו לצלול פנימה ולשים את כל הביצים בסל אחד, כמו שאומרים.

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

  • אז אקרא להם: זחילה, הליכה, ריצה קלה וריצה.

  • אז בשלב הזחילה, המטרה שלנו הייתה להכיר את Compose.

  • התחלנו עם דף עם נפח תנועה נמוך.

  • זה יכול להיות דף ההגדרות, רישיונות של צד שלישי וכו'.

  • המטרה העיקרית שלכם היא להכיר את ספריית Compose.

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

  • ואז צריך להתחיל להעביר את כל התשתית של האפליקציה ולהבין איך היא פועלת ב-Compose.

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

  • אז בעצם כל הדברים האלה.

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

  • אחרי שהתרגלנו והרגשנו בנוח, החלטנו לעבור להליכה.

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

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

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

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

  • יש לכם מחסנית עיבוד שכולה ב-Compose ואחת שנמצאת בתצוגות.

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

  • אבל ככל שתשתמשו יותר ב-Compose, הבעיה הזו תיעלם.

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

  • אחרי ההליכה, עוברים לריצה קלה.

  • אז זה קורה כשאנחנו כבר מרגישים מאוד מאוד בנוח.

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

  • אז מה שעשינו זה להשאיר את ספריית הניווט ואת השימוש ב-Fragments, אבל כל מסך בנפרד הוטמע באופן מלא ב-Compose.

  • פשוט גרמנו ל-Fragment להחזיר את ה-ComposeView עצמו.

  • לכן, אתם יכולים לצפות לשיפור בזמן האחזור ובקפיצות.

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

  • גם Compose עצמו מבצע רמות מסוימות של שמירה במטמון ברמת ComposeView.

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

  • אז אחרי זה, עברנו לריצה.

  • זה הזמן להשקיע את כל המאמצים.

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

  • אז מעל המסכים, יש לנו את הפעילות.

  • לכן, צריך להעביר את ComposeView לשורש של הפעילות.

  • והרבה מהקוד שלכם ייראה יחסית דומה.

  • אתם עדיין מנסים לבצע הוראת ניווט, למשל לעבור ממסך אחד לאחר.

  • אבל במקום לבצע טרנזקציות של Fragment, אתם קוראים לפונקציה קומפוזבילית.

  • אתם יכולים לעשות את זה בנוסף לספריית Nav2 או לספריית Nav3, לפי בחירתכם.

  • אנחנו לא העברנו את כל המסכים שלנו.

  • כבר אמרתי שיש לנו הרבה כאלה.

  • לכן יצרנו תאימות ל-Fragment, שמאפשרת לכם ליצור מסך שמבוסס על Fragment ולהשתמש ב-AndroidFragment wrappers של Compose כדי לעשות את זה.

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

  • אבל אתם גם מקבלים יכולות חדשות.

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

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

  • אתם יכולים גם לנצל את כל הגמישות של האנימציה ב-Compose בזמן שאתם מבצעים את המעבר הזה.

  • עכשיו אעביר את רשות הדיבור לקיריל, שידבר על עוד כמה יכולות.

עיצוב וביצועים

  • תודה, ג'ון.

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

  • בעולם של View, היה קוד Java וקצת אחר כך קוד Kotlin, ואז היו משאבי XML, משאבים כמו צבעים, מחרוזות, מידות, פריסות, עיצובים וסגנונות.

  • התהליך היה כזה: כל משאבי ה-XML האלה קומפלו לטבלת משאבים שנכללה ב-APK, והיא הייתה די סטטית.

  • היה ממשק API Resources.Theme.applyStyle שאפשר להשתמש בו באופן דינמי בזמן הריצה כדי להחיל סגנון מותאם אישית על היררכיית ממשק המשתמש.

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

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

  • היה קצת קשה לבנות מודל מנטלי נכון של היררכיית הסגנונות בעולם ה-XML הזה.

  • ולבסוף, לא הייתה תצוגה מאוחדת אחת ב-Android Studio או בכל כלי למפתחים אחר שאפשרה לכם לגשר על הפער בין עולם ה-Java, עולם הקוד ועולם ה-XML.

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

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

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

  • אנחנו מיישמים את שכבת העל הזו של התאמת העיצוב של Google Material Design עם ערכת צבעים בהתאמה אישית שנוצרה על ידי הספרייה Material Color Utilities, שזמינה לשימוש ב-GitHub.

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

  • כך מפתחי Android יכולים להשתמש ביכולת המלאה של עיצוב דינמי.

  • הכול נעשה בקוד, הכול נעשה ב-Kotlin, מה שאומר שהרבה יותר קל לבנות את המודל המנטלי המתאים של אופן הפעולה של הכול, והרבה יותר קל לנפות באגים.

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

  • שיקולי ביצועים: יצירת ערכת צבעים מלאה באמצעות ספריית Material Color Utilities כרוכה בתשלום.

  • הוא כרוך בתקורה מסוימת.

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

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

  • אתם יכולים להשתמש באותה ספריית Material Color Utilities בזמן ה-build כדי ליצור מראש את ערכות הצבעים האלה על סמך צורכי המיתוג או המוצר שלכם, ולהעביר את העומס הזה לזמן ה-build.

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

  • אז תלוי בכמות שמשתמשים בהם, עשרות, מאות, זה מתחיל להצטבר.

  • ובשלב מסוים, כדאי להתחיל לבדוק את העלות של כל המשתנים המקומיים המשולבים האלה.

  • וזו דוגמה למה שציינתי, כמו יכולות עיצוב דינמיות אמיתיות בזמן ריצה של Compose.

  • כאן יש לנו ארבעה רבעים, אותם רכיבים חזותיים, אותו כרטיס אירוע, נקרא לזה כך.

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

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

  • ההטמעה של הכרטיס זהה לחלוטין בכל ארבעת המקרים האלה.

  • ההבדל היחיד הוא ששכבת העל של התאמת העיצוב של Google Material Design שעוטפת את הכרטיס נוצרת או מוגדרת באמצעות ערכת צבעים שנוצרת באופן דינמי על סמך הצבע הדומיננטי של התמונה: כחול, סגול, צהוב ואדום.

  • כל שאר הפרטים נשארים ללא שינוי.

  • אין צורך להרוס וליצור מחדש את הפעילות.

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

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

  • ועכשיו נחזור לג'ון לחלק הבא.

התאמה לעומס (scaling) של אמינות ומהירות

  • כן.‏

  • אז זו עוד דוגמה לגמישות שקיריל דיבר עליה.

  • בואו נדבר על אמינות ומהירות.

  • לכן, כל המפתחים והעסקים מחפשים דרכים לכתוב קוד איכותי במהירות.

  • בואו נראה איך Compose עזר ל-Play לעשות את זה.

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

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

  • למי שלא מכיר את אופן הפעולה, העיקרון הבסיסי הוא שיש מקור נתונים.

  • מקור נתונים מספק נתונים.

  • הנתונים האלה יכולים להפוך לממשק משתמש ספציפי, שאנחנו מפיקים כמודל של ממשק משתמש.

  • ואז Compose יכול בקלות לצפות בזה, פשוט על ידי קריאה למאפיין ערך במצב הזה.

  • זה סוג של החיצים לאורך הצד העליון של התרשים הזה.

  • ואז האירועים זורמים בכיוון ההפוך.

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

  • אז הכול עובר דרך הלולאה הפשוטה הזו.

  • היתרון העיקרי שראינו הוא שזה עוזר לקצר את תקופת ההסתגלות.

  • לא צריך יותר לחפש איפה כל הקריאות האלה מתרחשות ב-thread הראשי או ב-threads האחרים.

  • הוא פועל בלולאה כללית אחת.

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

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

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

  • אז זה באמת שיפר את זמן האחזור של הטעינה בחנות, אתם יודעים, בעשרות, 50 אלפיות השנייה או משהו כזה.

  • זה היה די מרשים מבחינתנו.

  • בנוסף לזרימת נתונים חד-כיוונית, היתרון הגדול השני של Compose הוא ממשק משתמש דקלרטיבי.

  • קיריל נגע בזה קצת.

  • אז גם המפתחים ב-Play ממש נהנו מזה.

  • תהליך הבקרה של ממשק המשתמש נמצא עכשיו בקובץ אחד.

  • בצד שמאל יש דוגמה פשוטה יחסית.

    @Composable
    fun PurchaseRow(onClick: () -> Unit, modifier: Modifier) {
      Row(modifier) {
        Text("20% off sale")
        if (LocalExpts.current.useButtonV2) {
          ButtonV2("Buy", onClick = onClick)
        } else {
          ButtonV1("Buy", onClick = onClick)
        }
      }
    }
  • אנחנו מחליפים בין שתי הטמעות של כפתורים על סמך דגל ניסוי.

  • במקום לקרוא כמה קובצי תצוגה או קובצי מקטעים וקובצי XML, פשוט קוראים מלמעלה למטה, וזה הרבה יותר פשוט.

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

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

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

  • זה יתרון עצום בשבילנו.

הכנת הקרקע למודלי LLM

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

  • אני בטוח שהרבה מכם ניסו או עשו את זה עם ה-LLM האהוב עליהם.

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

  • אבל יש לו גם מגבלות.

  • ומה ש-Play באמת רואה זה שהוא לא מבין את בסיס הקוד שלך, נכון?

  • הוא לא יודע אילו רכיבים כבר בניתם וצריך להשתמש בהם שוב, והוא לא יודע את השמות של אסימוני העיצוב.

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

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

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

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

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

  • אז בסופו של דבר מקבלים משהו כמו מה שהיה לנו קודם, שעובר למה שקורה אחרי.

  • אין כאן את התיבות התוחמות כי הן היו מוסיפות הרבה רעש לתרשים.

  • אבל אפשר לראות שהשמות של הצבעים והטיפוגרפיה שמוגדרים בקוד הוחלפו ב-title large וב-on surface.

  • שמות הרכיבים, כמו כותרת הכרטיס ותג הסמל, מסומנים בבירור.

  • כך אפשר למצוא אותם בבסיס הקוד.

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

  • לכן, אתם לא צריכים להוסיף תוויות מותאמות אישית לכל המוצרים האלה כל הזמן.

  • משלבים את זה עם חתימת שיטה כמו זו שמופיעה למטה, OfferCard, ואז היא יודעת שהכותרת, endDate והתמונה הן דינמיות.

  • אנחנו לא צריכים להגדיר אותם בתוך הקוד.

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

  • כתוצאה מכך, אנחנו יוצרים הרבה יותר קוד.

  • אני מעביר את רשות הדיבור לקיריל, שיסביר איך אנחנו שומרים על האיכות.

אוטומציה של איכות

  • בסדר.

  • תודה, ג'ון.

  • אז בהמשך לנושא הזה של פיתוח בעזרת LLM ו-Agent Assist, נתחיל בצד של עיצוב ה-UX.

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

  • אולי זה חומר לימוד.

  • אולי זו מערכת העיצוב המותאמת אישית שלכם.

  • ובאופן ספציפי, אתם רוצים שהתבניות האלה יכללו תמיכה מובנית במעבר בין מצב בהיר למצב כהה, ובין מצבי ניגודיות רגילה, בינונית וגבוהה שהוצגו ברמת Android לפני כמה שנים.

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

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

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

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

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

  • וזה מפחית באופן משמעותי את עלויות העיצוב וההטמעה.

  • בכל מה שקשור להטמעה, אנחנו מסתמכים מאוד על כללי Lint בסיסיים ומותאמים אישית.

  • יש כמה כללי Lint בסיסיים שאני רוצה לציין. הראשון הוא FrequentlyChangingValueDetector, שעוזר לזהות מקורות של קומפוזיציות מחדש מיותרות, שעלולות לגרום לזמן אחזור ולתנועות קופצניות. השני הוא ScaffoldPaddingDetector, שמסמן מקרים שבהם אנחנו משתמשים ברכיב ה-Scaffold של Material Compose, אבל מתעלמים מהריפודים הנכנסים.

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

  • ולסיום, BoxWithConstraints, שכולל שיקולי ביצועים מסוימים.

  • יכול להיות שיידרשו שני פריימים כדי לפרוס את הכול כמו שצריך.

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

  • לגבי אוטומציה של עיצוב, שוב, אסימוני צבע, אסימוני טיפוגרפיה, אסימוני צורה.

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

  • יש לנו כלל Lint שמסמן שימוש ברכיבי Material 2.

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

  • יש לנו כלל Lint מותאם אישית שמונע מאנשים לקרוא צבעים, למשל, מקובצי XML מדור קודם.

  • אנחנו רוצים להשתמש ב-Compose כברירת מחדל ורק ב-Compose למסכים חדשים.

  • ולרכיבי Text composable, במיוחד במערכת Material Design, יש חלופות לסגנון ולצבע.

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

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

  • אז זה כלל Lint שיש לנו.

  • והאחרון, בדומה ל-ScaffoldPaddingDetector, יש לנו כלל Lint מותאם אישית שאוכף שכל פונקציה קומפוזבילית שיש לנו משתמשת ב-modifier הקלט שלה.

  • שוב, כדי למנוע, למשל, שימושים חדשים, כמו מיקום שגוי, או חוסר התאמה לרקע הנכנס, או כל דבר אחר.

סיכום

  • אלה שלוש הנקודות העיקריות שאנחנו רוצים שתזכרו מהמצגת הזו.

  • הראשונה היא שהיום, בסוף 2026, לדעתנו Compose היא ערכת כלים בשלה לממשק משתמש, שהוכיחה את עצמה בקנה מידה גדול.

  • מערכת Android עצמה מבוססת קודם כל על Compose.

  • מוקדם יותר השנה, בכנס Google I/O, הודענו שכל ספריות ממשק המשתמש וכל התהליכים של הסוכנים מבוססים קודם כל על Compose.

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

  • תודה שהקדשתם לנו זמן היום. בעוד כמה דקות, ג'ון ואני נהיה בחוץ כדי לענות על כל שאלה שיש לכם.

  • ושוב, תודה על הזמן שהקדשת לנו.

קוד

קטעי קוד

קטע קוד ב-Kotlin בדקה 16:09 בסרטון "Scaling reliability and velocity"
@Composable
fun PurchaseRow(onClick: () -> Unit, modifier: Modifier) {
  Row(modifier) {
    Text("20% off sale")
    if (LocalExpts.current.useButtonV2) {
      ButtonV2("Buy", onClick = onClick)
    } else {
      ButtonV1("Buy", onClick = onClick)
    }
  }
}