مطالعات موردی

چگونه مهندسان Instagram Direct معماری میانای کاربر مبتنی بر هوش مصنوعی را با Jetpack Compose ساختند و هزینه هر جلسه عامل را ۳۳٪ کاهش دادند

‫۱۱ دقیقه خواندن
مشاهده نمایه Pavlo Stavytskyi مشاهده نمایه Rebecca Franks
‫ Pavlo Stavytskyi و Rebecca Franks

این پست وبلاگ با همکاری تیم Meta نوشته شده است

Instagram Direct یکی از سطوح اصلی در Instagram است که هر روز میلیاردها پیام کاربر را مدیریت می‌کند. درطول سال‌ها تکرار، تیم هر ریزبهینه‌سازی ممکن را از سیستم قدیمی Android View استخراج کرد. بااین‌حال، حفظ و گسترش یک سطح قدیمی به‌شدت بهینه‌سازی‌شده، بدهی فنی و سربار مهندسی قابل‌توجهی ایجاد می‌کند، به‌ویژه زمانی که تیم‌ها به‌طور فزاینده‌ای از واسط کاربر اعلانی و دستیاران کدنویسی هوش مصنوعی استفاده می‌کنند. 

استفاده از Jetpack Compose برای Instagram Direct فراتر از نوسازی معمول میانای کاربر بود. این تیم یک پایگاه کد میانای کاربر مبتنی بر هوش مصنوعی ساخت که ۵۰٪ کوچک‌تر از پیاده‌سازی اصلی است، درحالی‌که زمان اجرای عامل هوش مصنوعی را ۳۵٪ کاهش می‌دهد، تبادلات مهندس-عامل را ۳۲٪ کمتر می‌کند، و هزینه ژتون را ۳۳٪ کاهش می‌دهد. این تیم با مشارکت نزدیک با Google، ضمن حفظ سطح عملکرد بالا، Jetpack Compose را اتخاذ کرد. ازطریق بهینه‌سازی‌های عملکرد، Meta و Google‏ Compose را نه تنها برای Instagram، بلکه برای بوم‌سازگان گسترده‌تر توسعه‌دهندگان Android نیز بهبود بخشیدند.

مدرن‌سازی پایگاه کد در مقیاس انبوه

هوش مصنوعی به‌سرعت به همراهی روزانه برای مهندسان در این صنعت تبدیل شده است و اعمال آن بر پایگاه کد بزرگی مانند Instagram درحال‌حاضر بهره‌وری واقعی را افزایش می‌دهد. تیم Instagram Direct هدف بلندپروازانه‌تری را تعیین کرد. تیم به‌جای اینکه صرفاً ابزارهای هوش مصنوعی را به کد موجود ارجاع دهد، پایگاه کد و معماری آن را به‌گونه‌ای بازطراحی کرد که از ابتدا با هوش مصنوعی سازگار باشد. این کار تأثیر هوش مصنوعی را بسیار فراتر از آنچه که صرفاً با به‌روزرسانی کد قدیمی قابل‌دستیابی است، افزایش داد.

تیم Instagram Direct،‏ Jetpack Compose را به‌عنوان مؤلفه کلیدی برای ساختن معماری میانای کاربر مبتنی بر هوش مصنوعی انتخاب کرد. ماهیت اعلانی آن تضمین می‌کند که کد مختصر، قابل‌پیش‌بینی، و ازنظر ساختاری برای مدل‌های هوش مصنوعی آسان‌تر باشد تا بتوانند درباره آن استدلال کنند، با عوارض جانبی کمتر، حالت ضمنی کمتر، و مرزهای مؤلفه واضح‌تر.

انتقال به Jetpack Compose به برنامه‌ریزی دقیق نیاز داشت. صدها میلیون نفر هر روز در اینستاگرام پیام ارسال می‌کنند، بنابراین انتقال باید تدریجی، روان و بدون هیچ‌گونه اختلالی در تجربه کاربری انجام می‌شد، درحالی‌که تیم درحال بازسازی معماری زیربنایی آن بود. برای نشان دادن مقیاس این چالش: مؤلفه‌های تکی میانای کاربری می‌توانند در بیش‌از ۱۶۰ جایگشت حالت متمایز ارائه شوند، و یک صفحه مکالمه به‌تنهایی بیش‌از ۲۰۰ نوع پیام متمایز را مدیریت می‌کند.

Product Design 1.png

هنگام انتقال پایگاه کد با این اندازه به Compose، وسوسه‌انگیز است که راه آسان را انتخاب کنید و مؤلفه‌های Compose UI را در سلسله‌مراتب View موجود جاسازی کنید. به‌عنوان یک گام افزایشی درطول انتقال تدریجی، این کاملاً معتبر است. بااین‌حال، در درازمدت، ادغام Compose در پایگاه کد مبتنی بر View چالش‌برانگیز است. ابزارهای هوش مصنوعی اغلب مسیری را انتخاب می‌کنند که کمترین مقاومت را داشته باشد. اگر کد میانای کاربری اعلانی و امری را باهم ترکیب کنید، هوش مصنوعی احتمالاً آن‌ها را به‌اشتباه باهم ادغام می‌کند و باعث ایجاد اشکال‌های جزئی، بدهی فنی، و پس‌رفت عملکرد می‌شود. 

ساختن معماری میانای کاربر مبتنی بر هوش مصنوعی

در مقیاس Instagram، درجه‌ای از انتزاع معماری اجتناب‌ناپذیر است و این همان چیزی است که برنامه را با رشد آن قابل نگهداری می‌کند. الگوی رایجی را درنظر بگیرید که در آن هر نوع مورد RecyclerView به‌عنوان فرزند کلاس پایه سفارشی RecyclerViewItem مدل‌سازی می‌شود که قلاب‌های چرخه حیات معمول مانند onBind را نشان می‌دهد.

نمونه ۱

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 به مورد پاک‌سازی می‌شود، همان مشکلات باقی می‌مانند.

نمونه ۲

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

    ...
  }
}

این یک مثال ساده است، اما مسئله‌ای گسترده‌تر را نشان می‌دهد: هرچه مرزهای کمتری برای هوش مصنوعی تعیین شود، کیفیت کدی که درطول زمان تولید می‌کند پایین‌تر خواهد بود. حفاظ‌ها و مهارت‌ها کمک می‌کنند، اما به‌تنهایی کافی نیستند، زیرا وقتی هوش مصنوعی با اصطکاک مواجه می‌شود، اغلب برای رفع انسداد خود، آن‌ها را دور می‌زند.

برای اینکه پایگاه کد با هوش مصنوعی سازگار باشد، باید از دو قانون کاربردی پیروی کند: 

  • وابستگی به بافت سفارشی را به‌حداقل برسانید. هرچه عامل هوش مصنوعی برای ایجاد تغییر صحیح به دانش سفارشی‌تر و مختص پایگاه کد نیاز داشته باشد، کیفیت برونداد آن پایین‌تر خواهد بود. هرچه پایگاه کد به روال‌های مطلوب شناخته‌شده نزدیک‌تر باشد، نتایج هوش مصنوعی بهتر خواهد بود.
  • پایگاه کد مبتنی بر هوش مصنوعی باید مرزهای خودش را اعمال کند. وصله کردن شکاف‌های طراحی با مهارت‌های هوش مصنوعی مقیاس‌پذیر نیست، زیرا هر مهارتی که در بافت بار می‌شود هزینه توکن دارد و می‌تواند عملکرد عامل را کاهش دهد. درعوض، خود معماری باید این بار را به دوش بکشد. عوامل هوش مصنوعی به‌طور طبیعی مسیری را انتخاب می‌کنند که کمترین مقاومت را داشته باشد، بنابراین طراحی باید به‌گونه‌ای باشد که این مسیر به کد صحیح و باکیفیت منجر شود، درحالی‌که بیان تصمیمات طراحی ضعیف را دشوار و پرهزینه کند.

مورد فهرست همچنان می‌تواند با انتزاع خودش نمایش داده شود، اما در این حالت، همه کد Compose در سازنده قرار دارد، بنابراین به اعضا یا وضعیت کلاس دسترسی ندارد و تنها منبع آرگومان‌های آن سازنده است. این کار باعث می‌شود که با تابع ساده @Composable معادل شود و درعین‌حال با معماری موجود مطابقت داشته باشد.

نمونه ۳

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 را تشکیل می‌دهند باید با همتایان قدیمی خود همزیستی می‌کردند و هر دو به‌طور موازی نگهداری می‌شدند. گردش‌های کار هوش مصنوعی با تسریع فرایند نوشتن حجم عظیمی از کد، به ممکن شدن این انتقال موازی کمک کردند. این رویکرد به تیم Direct اجازه داد تا انتقال را در زمان بی‌سابقه‌ای انجام دهد، بدون اینکه بقیه تیم را مختل کند، که به ارائه ویژگی‌هایی ادامه دادند که تجربه میلیون‌ها نفر را هر روز بهبود می‌بخشد.

چندین مهندس عامل‌های هوش مصنوعی خود را دربرابر پایگاه دانش مشترکی از مهارت‌ها و قراردادهای قابل‌استفاده مجدد که درطول انتقال ساخته شده بود اجرا کردند. این کار باعث شد گردش کار و روال‌های مطلوب در سراسر تیم همگام‌سازی شود، به‌جای اینکه هر مهندس مجبور باشد آن‌ها را دوباره کشف کند. در هر سطح، تیم انتقال را در مراحل زیر انجام داد:

  • همه کدهای Compose را با هوش مصنوعی بنویسید.
  • آن را صیقل دادیم، موارد حاشیه‌ای را مدیریت کردیم، و شکاف‌های عملکردی را بستیم تا اینکه واسط کاربر در یک آزمایش عمومی برای کاربران واقعی عرضه شد.

تقسیم کار به دو مرحله برای هر صفحه به یک مهندس اجازه می‌دهد تا به‌سرعت در کل سطح حرکت کند و معماری و موارد پیچیده را از ابتدا حل کند. با آماده شدن این زیرساخت، دیگران می‌توانند بدون توقف برای اتخاذ تصمیمات فنی، روی آماده‌سازی واسط کاربر برای تولید تمرکز کنند و سرعت کلی انتقال را بالا نگه دارند.

نتایج انتقال، رویکرد را تأیید کرد. برای سطوح منتقل‌شده Instagram Direct،‏ Jetpack Compose به تیم اجازه داد تا مقدار کل کد میانای کاربر را تا ۵۰٪ کاهش دهد. کد کمتر برای تولید توسط هوش مصنوعی با خروجی با کیفیت بالاتر و هزینه کمتر برای هر تکلیف همراه است. 

Quote-Pavlo-New.jpg

یک تحلیل داده داخلی از پایگاه کد Android برای Instagram Direct، جلسات عامل هوش مصنوعی را که روی Compose UI کار می‌کردند با همان وظایف بااستفاده از Android Views مقایسه کرد. افزایش کارایی در دو بعد مشخص بود:

  • به‌ازای هر نویسه از کد نهایی: Compose به ۳۲٪ تبادل کمتر بین مهندس و عامل و ۳۵٪ زمان اجرای کمتر عامل (زمان سپری‌شده از وقتی که عامل شروع به کار روی درخواست مهندس می‌کند تا زمانی که پاسخ را برمی‌گرداند) نیاز داشت.
  • در هر جلسه نماینده: هزینه کلی توکن با Compose درمقایسه با Views تا ۳۳٪ کاهش یافت.

ما هم بازدهی خروجی و هم تعداد جلسه‌های معمول را گزارش می‌کنیم زیرا این دو نتیجه به‌طور مستقل مفید هستند. ارقام مربوط به تبادلات مهندس-عامل و زمان اجرا، مصرف منابع را به‌ازای هر واحد خروجی نهایی مقایسه می‌کنند، درحالی‌که رقم مربوط به ژتون، هزینه کل را برای یک جلسه معمول عامل مقایسه می‌کند.

داده‌ها همچنین تفاوت ثابتی را در نحوه مدیریت کدهای پیچیده یا شکننده توسط این دو چارچوب نشان داد. Meta این موضوع را بااستفاده از امتیاز ریسک تغییرات کد ردیابی می‌کند که کیفیت کلی کد و احتمال ایجاد حوادث تولید توسط تغییر را ارزیابی می‌کند. این تحلیل کارایی منابع عامل را بااستفاده از ترکیبی از مصرف کد، زمان اجرای عامل، و تعاملات مهندس با عامل اندازه‌گیری کرد. با افزایش امتیاز خطر فایل‌ها، جلسه‌های عامل هوش مصنوعی به‌طور طبیعی ازنظر بهره‌وری منابع ضعیف‌تر می‌شوند. 

وقتی امتیاز ریسک انباشته‌شده فایل دوبرابر می‌شود، میانای کاربر پیاده‌سازی‌شده با «نماهای Android» کارایی منابع عامل را تا ۳۰٪ کاهش می‌دهد (به‌ازای هر نویسه واردشده). در شرایط مشابه، کاهش با Jetpack Compose UI فقط ۹٪ است

ازطریق مشارکت بین Google و Meta، تیم Instagram Direct دیدگاه جدیدی را برای پذیرش Compose به ارمغان آورد — نزدیک شدن به آن ازطریق لنز آمادگی هوش مصنوعی پایگاه کد، نه فقط بازنویسی واسط کاربر. این کار نشان داد که Compose به‌عنوان پایه‌ای برای ساختن پایگاه‌های کد و معماری‌های مبتنی بر هوش مصنوعی، به‌ویژه وقتی در مقیاس برنامه‌هایی مانند Instagram اعمال می‌شود، چقدر قدرتمند است.

بهینه‌سازی‌های عملکرد 

Instagram Direct یکی از بخش‌های جدایی‌ناپذیر برنامه است و افراد انتظار دارند که همیشه سریع و پاسخگو باشد. پذیرش Jetpack Compose به‌طور مؤثر به‌معنای بازنویسی اساسی میانای کاربر بود و هدف اصلی حفظ تجربه باکیفیت بدون پس‌رفت بود.

سال‌ها تکرار، پیاده‌سازی قدیمی مبتنی بر View در Instagram را به سطح عملکردی فوق‌العاده بالا رسانده بود و تیم باید ضمن انتقال به چارچوب کاملاً جدید واسط کاربر، به همان استاندارد دست می‌یافت.

اینستاگرام صدها، اگر نه هزاران، سنجه عملکرد را اندازه‌گیری می‌کند.  برای پذیرش Compose، سه مورد زیر مهم‌ترین بودند:

  • زمان تعامل - مدت زمان بین باز کردن صفحه تا امکان استفاده از آن.
  • زمان بار شدن کامل - مدت زمان بین باز شدن صفحه تا زمانی که همه محتوا (مثلاً تصاویر) کاملاً بار می‌شود.
  • عملکرد پیمایش - میزان روان بودن پیمایش صفحه، بدون افت فریم.

این سنجه‌ها در زمان اجرا در تولید ردیابی می‌شوند و امکان اجرای آزمون‌های آ/ب را برای مقایسه «رابط کاربری Compose» منتقل‌شده با رابط کاربری قدیمی و ارزیابی تأثیر عملکرد این تلاش فراهم می‌کنند.

یک روش معمول برای انجام چنین انتقالی این است که از کوچک شروع کنید، چند مؤلفه رابط کاربری را منتقل کنید، داده‌ها را جمع‌آوری کنید، و رفتار آن‌ها را مطالعه کنید. هرچند این نتایج اولیه مفید هستند، اما فقط تصویری جزئی ارائه می‌دهند و موارد منفی کاذب را دربرابر پذیرش Compose ارائه می‌دهند زیرا:

  • غیرنماینده — یک مؤلفه میانای کاربر منتقل‌شده می‌تواند داده‌های مفیدی درباره عملکرد کلی آن در یک صفحه خاص ارائه دهد. بااین‌حال، مؤلفه‌های مختلف به دلایلی که قابل‌تعمیم نیستند رفتار متفاوتی دارند، بنابراین همیشه نمی‌توانید از آن برون‌یابی کنید.
  • هزینه تعامل‌پذیری — یک قطعه کوچک Compose در داخل یک پایگاه کد View بزرگ، هزینه پل‌سازی غیرقابل‌پیش‌بینی بین دو سیستم را پرداخت می‌کند. این سربار اندازه‌گیری را تحریف می‌کند، بنابراین نتایج اولیه در مقیاس کوچک نشان‌دهنده آنچه که انتقال کامل واقعاً به‌نظر می‌رسد نیست.

نتیجه این است که انتقال‌های کوچک، هرچند مفید، همیشه تأثیر کامل Compose را منعکس نمی‌کنند. هرچه سطح بیشتری به‌صورت سرتاسر و بدون وقفه پل‌سازی منتقل شود، تصویر ازنظر عملکرد واضح‌تر و بهتر می‌شود.

صفحه‌های اصلی در Instagram Direct براساس فهرست‌های طولانی از انواع مختلف موارد ساخته شده‌اند که در ابتدا با RecyclerView پیاده‌سازی شده بودند. این معماری برای مقیاس‌پذیری به انتزاع‌های سفارشی متکی است، اما همچنان به چرخه حیات سیستم مبتنی بر View محدود است.

Diagram 1.png

وظیفه اصلی تیم، انتقال تدریجی چند صد مورد فهرست جداگانه به Compose در معماری موجود مبتنی بر RecyclerView بود، که آن‌ها را در گروه‌های کوچک مستقل تحت آزمایش‌های A/B در تولید عرضه کردند — همه این‌ها بدون تغییرات قابل‌مشاهده در تجربه پیام‌رسانی کاربر انجام شد.

بزرگ‌ترین نقطه‌ضعف چنین راه‌اندازی‌ای وابستگی قابل‌توجه به سیستم قدیمی View ازطریق معماری اصلی RecyclerView است، حتی پس‌از انتقال کامل هر مورد فهرست به Compose. به‌عنوان گام طبیعی بعدی، تیم تصمیم گرفت روی جایگزین کردن معماری هسته مبتنی بر RecyclerView با جایگزین Compose-native (یعنی LazyColumn) سرمایه‌گذاری کند.

این یعنی مؤلفه‌های Compose UI باید از چارچوبی که در آن قرار دارند انتزاع شوند، درحالی‌که همچنان با هر دو RecyclerView و LazyColumn به‌طور هم‌زمان سازگار باشند. به همان اندازه، توانایی جابه‌جایی بین این دو در زمان اجرا ازطریق پرچم‌های ویژگی برای فعال کردن آزمایش A/B مهم است.

Diagram 2.png

درحالی‌که موارد جدید Compose به‌طور بومی با LazyColumn سازگار هستند و می‌توانند به درخت ترکیب‌بندی بدون وقفه متصل شوند، یک میانای برنامه‌سازی کاربردی تعامل‌پذیری نیز ایجاد شده است تا آن‌ها را در RecyclerView نیز قرار دهد. این امر باعث شد که بتوانیم راه‌اندازی LazyColumn را تحت آزمایش A/B در کنار RecyclerView عرضه کنیم — با استفاده مجدد از همان موارد Compose و بهبود عملکرد، بدون ایجاد اختلال در کار بقیه اعضای تیم که درحال ساخت و اصلاح ویژگی‌ها بودند.

مقیاس، پیچیدگی، و حساسیت Instagram حتی به کوچک‌ترین رگرسیون‌ها چالشی منحصربه‌فرد برای Jetpack Compose ایجاد کرد. رسیدگی به این موارد مستلزم مشارکت عملی و تکراری بود. مهندسان Google و Meta با همکاری نزدیک با یکدیگر، سنجه‌ها را تجزیه‌وتحلیل کردند تا قابلیت‌های جدید Compose را برای برآورده کردن یا فراتر رفتن از معیارهای مبتنی بر View شناسایی و طراحی کنند. درنتیجه این مشارکت، موارد زیر به Jetpack Compose اضافه شده است: ترکیب‌بندی قابل‌توقف با LazyLayoutCacheWindows و ردیابی نمایان بودن. 

ترکیب‌بندی قابل‌توقف با LazyLayoutCacheWindows

ترکیب‌بندی قابل‌توقف (به‌طور پیش‌فرض در Compose 1.10 فعال است) به موارد فهرست تنبل پرهزینه اجازه می‌دهد تا به‌صورت افزایشی در فریم‌ها ترکیب شوند تا از لرزش جلوگیری شود. وقتی با LazyLayoutCacheWindow (اضافه‌شده در Compose 1.9) جفت شود، این ترکیب به‌طور قابل‌توجهی روان بودن پیمایش را بهبود می‌بخشد. در آزمایش داخلی اخیر در Meta، ترکیب ترکیب‌بندی «قابل‌توقف» با یک نمای LazyLayoutCacheWindow افت فریم بزرگ در دقیقه (LFDs/m) را درمقایسه با Compose معمولی حدود ۱۳٪ کاهش داد. Cache Window به‌تنهایی آن را حدود ۸٪ نسبت‌به همان خط مبنا کاهش داد. ‫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 بدون توجه به دستگاه، ۱۵۰dp از محتوای ترکیب‌شده را فراتر از لبه قابل‌مشاهده نگه می‌دارد.
  • Float: کسری از ناحیه نمایش. aheadFraction = 0.5f نیمی از صفحه را ازقبل ترکیب‌بندی می‌کند، بنابراین مقدار مطلق با ارتفاع صفحه مقیاس‌بندی می‌شود و از انواع مختلفی از ابعاد پشتیبانی می‌کند: بیشتر در رایانه لوحی یا دستگاه تاشو بازشده، کمتر در تلفن جمع‌وجور. 

تیم Instagram کسرهای اعشاری پنجره حافظه پنهان را به‌طور خاص برای ساختار محتوای Direct و اندازه‌های موارد تنظیم کرد. ازآنجایی‌که مقادیر ایده‌آل بسته به پارامترهای خاص واسط کاربر متفاوت است، یافتن تعادل مناسب نیاز به کمی آزمایش دارد.

گزارش‌گیری ظهور با onVisibilityChanged


‫API‏  onVisibilityChanged (اضافه‌شده در Compose نسخه ۱.۹.۰) یکی دیگر از نتایج کلیدی مشارکت فنی بین Google و Meta بود. این ویژگی به سطوح Jetpack Compose در مقیاس بزرگ روشی یکسان برای اطلاع از اینکه چه زمانی یک composable واقعاً روی صفحه قابل‌مشاهده است ارائه می‌دهد و جایگزین پیاده‌سازی‌های سفارشی و دستی می‌شود که در گذشته استفاده می‌شد. فقط در Instagram Direct، از این نشان‌های رؤیت‌پذیری در صدها فایل استفاده می‌شود تا از سنجه‌های کیفیت محصول که به نمایش واقعی عناصر میانای کاربر به افراد بستگی دارد پشتیبانی شود.

عملکرد راه‌اندازی

استفاده از Jetpack Compose برای Instagram Direct منجر به بهبود غیرمنتظره عملکرد در سایر سطوح برنامه شد. زمان اجرای Jetpack Compose هزینه آماده‌سازی دارد که فقط یک‌بار پرداخت می‌کنید، و چون پیام‌رسانی سطحی با ترافیک بالا است که اغلب در اوایل جلسه کاربر بازدید می‌شود، سایر سطوح در Instagram که به Compose متکی هستند، بهبود قابل‌توجهی در عملکرد داشتند.

عملکرد راه‌اندازی Compose UI در Instagram Direct بااستفاده از Baseline Profiles بهینه‌سازی شد. این نمایه‌ها مسیرهای کد داغ را در زمان نصب پیش‌کامپایل می‌کنند تا Compose از همان اولین راه‌اندازی به‌سرعت ارائه شود.

درس‌هایی از انتقال Instagram Direct به Jetpack Compose 

  • Jetpack Compose بازگشت سرمایه فوری دارد: برای بهره‌مندی از Compose، نیازی به استفاده از گردش‌های کاری پیشرفته هوش مصنوعی ندارید. با کاهش حدود ۵۰ درصدی کد، کد کمتری برای نگهداری وجود دارد و سطح بروز اشکال کاهش می‌یابد.
  • طراحی معماری مبتنی بر هوش مصنوعی منجر به دستاوردهای قابل‌توجهی شد، ازجمله کاهش ۳۵ درصدی زمان اجرای عامل هوش مصنوعی، کاهش ۳۲ درصدی تبادلات مهندس-عامل، و کاهش ۳۳ درصدی هزینه توکن.
  • اگرچه میان‌کنش‌پذیری‌های API و پشتیبانی زیادی برای ترکیب کردن «نماها» و Compose با یکدیگر وجود دارد، هدف این است که سطوح بزرگ‌تر را به‌جای مؤلفه‌های کوچک تکی منتقل کنید. این کار واسط کاربر را در یک سلسله‌مراتب ترکیب‌بندی واحد و بدون وقفه نگه می‌دارد و همه بهترین بهینه‌سازی‌های عملکرد بومی Compose را باز می‌کند.
  • جفت کردن ترکیب‌بندی «قابل‌توقف» با LazyLayoutCacheWindow: جفت کردن این دو باهم نتایج بهتری نسبت‌به پنجره‌های حافظه پنهان به‌تنهایی به‌همراه دارد. اگر فقط پنجره حافظه پنهان وجود داشته باشد، ممکن است یک مورد سنگین همچنان تلاش کند در یک مرحله ترکیب‌بندی شود، که این امر می‌تواند باعث فراتر رفتن از بودجه فریم شود.
  • در Compose مشارکت کنید! Meta با تیم Jetpack Compose همکاری کرده است تا بازخوردها و ایده‌های آن‌ها را در Compose پیاده‌سازی کند. کار کردن روی جعبه‌ابزار متن‌باز یعنی وقتی اشکال‌ها و بهبودهای عملکرد به‌صورت متمرکز انجام می‌شود، همه ما سود می‌بریم. پس، بازخوردتان را به ما اطلاع دهید!

استفاده از Jetpack Compose دستاوردهای قابل‌توجهی را در توسعه با کمک هوش مصنوعی به‌همراه داشت و درعین‌حال مهندسی روزانه میانای کاربر را در Instagram ساده‌تر کرد. رویکرد اعلانی کد تکراری را کاهش می‌دهد، استدلال درباره وضعیت را آسان‌تر می‌کند، و بهره‌وری کلی توسعه‌دهنده را بهبود می‌بخشد. تیم مهندسی Instagram مشتاقانه منتظر است تا Compose را به سطوح بیشتری در سراسر برنامه بیاورد و همکاری بین Google و Meta را ادامه دهد تا بهبودهای بیشتری را برای کاربران Instagram و Jetpack Compose به ارمغان بیاورد. 

اگر هنوز Compose را امتحان نکرده‌اید، اکنون با کمک هوش مصنوعی، انتقال به Jetpack Compose آسان‌تر از همیشه است.

سپاس‌گزاری. از Michal Zielinski و Matthew Du از Meta، و Andrei Shikov و George Mount از Google، به‌خاطر تلاش‌هایشان برای بهبود عملکرد Compose ازطریق همکاری بین Meta و Google سپاس‌گزاریم! همچنین از Gary Ye از Meta برای کمک به آوردن Compose به Instagram Direct و از Gopal Juneja از Meta برای حمایت از این تلاش ازطریق علم داده‌ها تشکر می‌کنیم!

نویسنده:
ادامه خواندن