কেস স্টাডিজ

ইনস্টাগ্রাম ডিরেক্ট-এর ইঞ্জিনিয়াররা কীভাবে জেটপ্যাক কম্পোজ ব্যবহার করে এআই-নেটিভ ইউআই আর্কিটেকচার তৈরি করেছেন এবং প্রতি এজেন্ট সেশনের টোকেন খরচ ৩৩% কমিয়েছেন

পড়তে ১১ মিনিট
Pavlo Stavytskyi এর প্রোফাইল দেখুন রেবেকা ফ্রাঙ্কসের প্রোফাইল দেখুন
Pavlo Stavytskyi এবং Rebecca Franks

এই ব্লগ পোস্টটি মেটা টিমের সহযোগিতায় লেখা হয়েছে।

ইনস্টাগ্রাম ডিরেক্ট হলো ইনস্টাগ্রামের অন্যতম প্রধান একটি প্ল্যাটফর্ম, যা প্রতিদিন শত শত কোটি ব্যবহারকারীর বার্তা আদান-প্রদান করে। বছরের পর বছর ধরে বারবার পরিবর্তনের মাধ্যমে, টিমটি পুরোনো অ্যান্ড্রয়েড ভিউ সিস্টেম থেকে সম্ভাব্য সব ধরনের সূক্ষ্ম অপটিমাইজেশন বের করে এনেছে। তবে, ব্যাপকভাবে অপটিমাইজ করা একটি পুরোনো প্ল্যাটফর্ম রক্ষণাবেক্ষণ ও সম্প্রসারণ করতে গিয়ে উল্লেখযোগ্য পরিমাণে টেকনিক্যাল ডেট এবং ইঞ্জিনিয়ারিং ওভারহেড তৈরি হয়, বিশেষ করে যখন টিমগুলো ক্রমবর্ধমানভাবে ডিক্লারেটিভ UI এবং AI কোডিং অ্যাসিস্ট্যান্ট ব্যবহার শুরু করেছে।

ইনস্টাগ্রাম ডিরেক্টের জন্য জেটপ্যাক কম্পোজ গ্রহণ করাটা একটি সাধারণ UI আধুনিকীকরণের চেয়েও বেশি কিছু ছিল। দলটি একটি AI-নেটিভ UI কোডবেস তৈরি করেছে যা মূল বাস্তবায়নের চেয়ে ৫০% ছোট , এবং এর মাধ্যমে AI এজেন্টের এক্সিকিউশন টাইম ৩৫% , ইঞ্জিনিয়ার-এজেন্ট বিনিময় ৩২% এবং টোকেন খরচ ৩৩% হ্রাস পেয়েছে । গুগলের সাথে নিবিড় অংশীদারিত্বে, দলটি উচ্চ পারফরম্যান্সের মান বজায় রেখে জেটপ্যাক কম্পোজ গ্রহণ করেছে। এই পারফরম্যান্স অপ্টিমাইজেশনের মাধ্যমে, মেটা এবং গুগল শুধুমাত্র ইনস্টাগ্রামের জন্যই নয়, বরং বৃহত্তর অ্যান্ড্রয়েড ডেভেলপার ইকোসিস্টেমের জন্যও কম্পোজকে উন্নত করেছে।

ব্যাপক পরিসরে কোডবেস আধুনিকীকরণ

শিল্পক্ষেত্রের প্রকৌশলীদের জন্য এআই দ্রুত এক নিত্যসঙ্গী হয়ে উঠেছে, এবং ইনস্টাগ্রামের মতো একটি বৃহৎ কোডবেসে এর প্রয়োগ ইতিমধ্যেই উৎপাদনশীলতায় প্রকৃত বৃদ্ধি এনেছে। ইনস্টাগ্রাম ডিরেক্ট টিম আরও একটি উচ্চাভিলাষী লক্ষ্য নির্ধারণ করেছিল। বিদ্যমান কোডের দিকে শুধু এআই টুল নির্দেশ করার পরিবর্তে, দলটি কোডবেস এবং এর আর্কিটেকচারকে এমনভাবে নতুন করে ডিজাইন করেছে যাতে এটি নকশাগতভাবেই এআই-নেটিভ হয়, যা শুধুমাত্র রেট্রোফিটিংয়ের মাধ্যমে অর্জিত ফলাফলের চেয়ে এআই-এর প্রভাবকে বহুগুণে বাড়িয়ে দেয়।

ইনস্টাগ্রাম ডিরেক্ট টিম একটি এআই-নেটিভ ইউআই আর্কিটেকচার তৈরির জন্য জেটপ্যাক কম্পোজকে একটি মূল উপাদান হিসেবে বেছে নিয়েছে। এর ডিক্লারেটিভ বৈশিষ্ট্য নিশ্চিত করে যে কোডটি সংক্ষিপ্ত, অনুমানযোগ্য এবং এআই মডেলগুলোর জন্য কাঠামোগতভাবে বোঝা সহজ হয়, সাথে থাকে কম সাইড ইফেক্ট, কম ইমপ্লিসিট স্টেট এবং সুস্পষ্ট কম্পোনেন্ট বাউন্ডারি।

জেটপ্যাক কম্পোজে স্থানান্তরের জন্য সতর্ক পরিকল্পনার প্রয়োজন ছিল। প্রতিদিন কোটি কোটি মানুষ ইনস্টাগ্রামে বার্তা পাঠায়, তাই এই স্থানান্তর প্রক্রিয়াটি ধাপে ধাপে ও মসৃণভাবে সম্পন্ন করতে হতো এবং এর নিচের ভিত্তিটি নতুন করে সাজানোর সময় ব্যবহারকারীর অভিজ্ঞতায় যেন কোনো ব্যাঘাত না ঘটে, সেদিকে খেয়াল রাখতে হতো। এই চ্যালেঞ্জের ব্যাপকতা বোঝানোর জন্য বলা যায়: প্রতিটি UI কম্পোনেন্ট ১৬০টিরও বেশি স্বতন্ত্র অবস্থার বিন্যাসে রেন্ডার হতে পারে এবং শুধুমাত্র একটি কথোপকথনের স্ক্রিনই ২০০টিরও বেশি স্বতন্ত্র ধরনের বার্তা পরিচালনা করে।

প্রোডাক্ট ডিজাইন 1.png

এই আকারের একটি কোডবেসকে কম্পোজে মাইগ্রেট করার সময়, সহজ পথ বেছে নিয়ে বিদ্যমান ভিউ হায়ারার্কির ভেতরে কম্পোজ UI কম্পোনেন্টগুলো এমবেড করে দেওয়ার একটি প্রবণতা দেখা যায়। একটি পর্যায়ক্রমিক মাইগ্রেশনের সময় একটি ক্রমবর্ধমান পদক্ষেপ হিসেবে, এটি পুরোপুরি বৈধ। তবে, দীর্ঘমেয়াদে, একটি ভিউ-ভিত্তিক কোডবেসের মধ্যে কম্পোজকে ইন্টিগ্রেট করা একটি চ্যালেঞ্জ তৈরি করে। AI টুলগুলো প্রায়শই সবচেয়ে সহজ পথটি বেছে নেয়। আপনি যদি ডিক্লারেটিভ এবং ইম্পারেটিভ UI কোড একসাথে মেশান, তাহলে AI সম্ভবত সেগুলোকে ভুলভাবে মিশ্রিত করবে, যার ফলে সূক্ষ্ম বাগ, টেক ডেট এবং পারফরম্যান্সের অবনতি ঘটবে।

একটি এআই-নেটিভ UI আর্কিটেকচার তৈরি করা

ইনস্টাগ্রামের মতো বিশাল পরিসরে, এক ধরনের আর্কিটেকচারাল অ্যাবস্ট্রাকশন অপরিহার্য, এবং এটিই অ্যাপটিকে বড় হওয়ার সাথে সাথে রক্ষণাবেক্ষণযোগ্য রাখে। একটি প্রচলিত প্যাটার্নের কথা ভাবুন, যেখানে প্রতিটি 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")
      }
    }
    
    ...
  },
)

এত বড় একটি কোডবেস মাইগ্রেট করা একটি বিশাল কাজ। দীর্ঘদিন ধরে, ডিরেক্ট UI-এর বেশিরভাগ অংশ জুড়ে থাকা শত শত UI কম্পোনেন্টকে তাদের পুরোনো সংস্করণগুলোর সাথে সহাবস্থান করতে হতো এবং উভয়কেই সমান্তরালভাবে রক্ষণাবেক্ষণ করা হতো। AI ওয়ার্কফ্লো বিপুল পরিমাণ কোড লেখার প্রক্রিয়াকে দ্রুততর করে এই সমান্তরাল মাইগ্রেশনকে সম্ভব করে তুলেছে। এই পদ্ধতির কারণেই ডিরেক্ট টিম রেকর্ড সময়ে মাইগ্রেশনটি সম্পন্ন করতে পেরেছে, এবং এর ফলে দলের বাকি সদস্যদের কাজে কোনো ব্যাঘাত ঘটেনি, যারা প্রতিদিন লক্ষ লক্ষ মানুষের অভিজ্ঞতা উন্নত করে এমন ফিচারগুলো সরবরাহ করে গেছেন।

মাইগ্রেশনের সময় তৈরি হওয়া পুনঃব্যবহারযোগ্য দক্ষতা ও প্রচলিত রীতির একটি সম্মিলিত জ্ঞানভান্ডারের উপর ভিত্তি করে একাধিক প্রকৌশলী তাদের নিজস্ব এআই এজেন্ট পরিচালনা করেন। এর ফলে প্রত্যেক প্রকৌশলীকে নতুন করে সেগুলো আবিষ্কার করতে না হয়ে, পুরো দল জুড়ে কর্মপ্রবাহ এবং সর্বোত্তম অনুশীলনগুলো সমন্বিত ছিল। প্রতিটি ক্ষেত্রে, দলটি নিম্নলিখিত পর্যায়গুলিতে মাইগ্রেশনটি সম্পন্ন করে:

  • সমস্ত Compose কোড AI দিয়ে লিখুন।
  • পাবলিক টেস্টে প্রকৃত ব্যবহারকারীদের কাছে UI-টি চালু করার আগ পর্যন্ত, এজ কেসগুলো সামলে এবং পারফরম্যান্সের ঘাটতিগুলো দূর করে এটিকে পরিমার্জন করা হয়েছিল।

প্রতিটি স্ক্রিনের জন্য কাজটিকে দুটি পর্যায়ে ভাগ করলে একজন ইঞ্জিনিয়ার দ্রুত পুরো সারফেসটি সম্পন্ন করতে পারেন এবং শুরুতেই আর্কিটেকচার ও জটিল এজ কেসগুলো ঠিক করে নিতে পারেন। এই ভিত্তি তৈরি হয়ে গেলে, অন্যরা নিজেরা সেই প্রযুক্তিগত সিদ্ধান্তগুলো নেওয়ার জন্য না থেমে UI-কে প্রোডাকশন-রেডি করার দিকে মনোযোগ দিতে পারেন, যা সামগ্রিক মাইগ্রেশনকে দ্রুত রাখে।

মাইগ্রেশনের ফলাফল এই পদ্ধতিটিকে যথার্থ প্রমাণ করেছে। মাইগ্রেট করা ইনস্টাগ্রাম ডিরেক্ট সারফেসগুলোর জন্য, জেটপ্যাক কম্পোজ টিমকে মোট UI কোডের পরিমাণ ৫০% কমাতে সাহায্য করেছে। AI-কে কম কোড তৈরি করতে হয়, যার ফলে উচ্চ-মানের আউটপুট পাওয়া যায় এবং প্রতি টাস্কের জন্য টোকেন খরচও কমে আসে।

Quote-Pavlo-New.jpg

ইনস্টাগ্রাম ডিরেক্ট-এর অ্যান্ড্রয়েড কোডবেসের একটি অভ্যন্তরীণ ডেটা বিশ্লেষণে, কম্পোজ ইউআই-তে কাজ করা এআই এজেন্ট সেশনগুলোর সাথে অ্যান্ড্রয়েড ভিউ ব্যবহার করে একই কাজগুলো সম্পাদনের তুলনা করা হয়েছে। দুটি ক্ষেত্রে কর্মদক্ষতার উন্নতি সুস্পষ্ট ছিল:

  • ল্যান্ড করা কোডের প্রতি ক্যারেক্টারের জন্য: কম্পোজের ফলে ইঞ্জিনিয়ার-এজেন্ট আদান-প্রদান ৩২% কম হয়েছে এবং এজেন্টের এক্সিকিউশন টাইম (একজন এজেন্ট যখন কোনো ইঞ্জিনিয়ারের অনুরোধে কাজ শুরু করে তখন থেকে প্রতিক্রিয়া জানানো পর্যন্ত অতিবাহিত সময়) ৩৫% কম লেগেছে ।
  • প্রতি এজেন্ট সেশনে: Views-এর তুলনায় Compose ব্যবহারে টোকেনের মোট খরচ ৩৩% কমেছে ।

আমরা আউটপুট দক্ষতা এবং সাধারণ সেশন সংখ্যা উভয়ই রিপোর্ট করি, কারণ এগুলো স্বতন্ত্রভাবে কার্যকরী ফলাফল। ইঞ্জিনিয়ার-এজেন্ট বিনিময় এবং কার্যসম্পাদনের সময়ের পরিসংখ্যান প্রতি ইউনিট সম্পন্ন আউটপুটের জন্য ব্যবহৃত সম্পদের তুলনা করে, অন্যদিকে টোকেনের পরিসংখ্যানটি একটি সাধারণ এজেন্ট সেশনের মোট খরচের তুলনা করে।

ডেটা থেকে আরও দেখা গেছে যে, দুটি ফ্রেমওয়ার্ক জটিল বা ভঙ্গুর কোড পরিচালনা করার পদ্ধতিতে একটি ধারাবাহিক পার্থক্য রয়েছে। মেটা কোড পরিবর্তনের একটি ঝুঁকি স্কোর ব্যবহার করে এটি ট্র্যাক করে, যা কোডের সামগ্রিক গুণমান এবং কোনো পরিবর্তনের ফলে প্রোডাকশনে কোনো দুর্ঘটনা ঘটার সম্ভাবনা মূল্যায়ন করে। এই বিশ্লেষণে টোকেন ব্যবহার, এজেন্টের এক্সিকিউশন টাইম এবং ইঞ্জিনিয়ার ও এজেন্টের মধ্যকার মিথস্ক্রিয়ার একটি সমন্বিত পরিমাপের মাধ্যমে এজেন্টের রিসোর্স দক্ষতা পরিমাপ করা হয়েছে। ফাইলগুলোর ঝুঁকি স্কোর যত বাড়তে থাকে, এআই এজেন্ট সেশনগুলো স্বাভাবিকভাবেই তত কম রিসোর্স-দক্ষ হয়ে ওঠে।

যখন কোনো ফাইলের সঞ্চিত ঝুঁকি স্কোর দ্বিগুণ হয় , তখন অ্যান্ড্রয়েড ভিউস দিয়ে তৈরি UI এজেন্টের রিসোর্স দক্ষতা ৩০% কমিয়ে দেয় (প্রতিটি ল্যান্ডেড ক্যারেক্টারের জন্য)। একই পরিস্থিতিতে, জেটপ্যাক কম্পোজ UI-এর মাধ্যমে এই হ্রাসের পরিমাণ মাত্র ৯%।

গুগল এবং মেটার অংশীদারিত্বের মাধ্যমে, ইনস্টাগ্রাম ডিরেক্ট টিম কম্পোজ ব্যবহারের ক্ষেত্রে একটি নতুন দৃষ্টিভঙ্গি নিয়ে আসে — তারা শুধু ইউআই পুনর্লিখনের দৃষ্টিকোণ থেকে নয়, বরং কোডবেসের এআই-প্রস্তুতির দৃষ্টিকোণ থেকে বিষয়টি বিবেচনা করে। এই কাজটি এআই-ফার্স্ট কোডবেস এবং আর্কিটেকচার তৈরির ভিত্তি হিসেবে কম্পোজের সক্ষমতা প্রকাশ করেছে, বিশেষ করে যখন এটি ইনস্টাগ্রামের মতো বৃহৎ পরিসরের অ্যাপে প্রয়োগ করা হয়।

কর্মক্ষমতা অপ্টিমাইজেশন

ইনস্টাগ্রাম ডিরেক্ট অ্যাপটির অন্যতম অপরিহার্য একটি অংশ, এবং ব্যবহারকারীরা আশা করেন যে এটি সব সময় দ্রুত এবং রেসপন্সিভ থাকবে। জেটপ্যাক কম্পোজ ব্যবহার করার ফলে ইউজার ইন্টারফেস (UI) ব্যাপকভাবে নতুন করে লিখতে হয়েছে, এবং মূল লক্ষ্য ছিল কোনো রকম অবনতি ছাড়াই উন্নত মানের অভিজ্ঞতা বজায় রাখা।

বছরের পর বছর ধরে পুনরাবৃত্তির মাধ্যমে ইনস্টাগ্রামের পুরোনো ভিউ-ভিত্তিক বাস্তবায়নটি ইতিমধ্যেই কর্মক্ষমতার এক অসাধারণ উচ্চ স্তরে পৌঁছেছিল, এবং সম্পূর্ণ নতুন একটি UI ফ্রেমওয়ার্কে স্থানান্তরের সময় দলটিকেও সেই একই মান বজায় রাখতে হতো।

ইনস্টাগ্রাম শত শত, এমনকি হাজার হাজার পারফরম্যান্স মেট্রিক পরিমাপ করে। কম্পোজ ব্যবহারের ক্ষেত্রে, নিম্নলিখিত তিনটি ছিল সবচেয়ে গুরুত্বপূর্ণ:

  • ইন্টারঅ্যাক্ট করার সময় - স্ক্রিন খোলার পর থেকে এটি ব্যবহার করতে পারার মধ্যবর্তী সময়।
  • সম্পূর্ণ লোড হতে লাগা সময় - স্ক্রিন খোলার পর থেকে সমস্ত বিষয়বস্তু (যেমন ছবি) সম্পূর্ণরূপে লোড হওয়া পর্যন্ত সময়।
  • স্ক্রল পারফরম্যান্স - ফ্রেম ড্রপ ছাড়াই স্ক্রিনটি কতটা মসৃণভাবে স্ক্রল করে।

প্রোডাকশনে রানটাইমে এই মেট্রিকগুলো ট্র্যাক করা হয়, যার ফলে মাইগ্রেট করা কম্পোজ UI-কে পুরোনো UI-এর সাথে তুলনা করে A/B টেস্ট চালানো এবং এই প্রচেষ্টার পারফরম্যান্সগত প্রভাব মূল্যায়ন করা সম্ভব হয়।

এই ধরনের মাইগ্রেশনের একটি সাধারণ উপায় হলো ছোট পরিসরে শুরু করা, যেখানে কয়েকটি UI কম্পোনেন্ট স্থানান্তর করে ডেটা সংগ্রহ করা হয় এবং সেগুলোর আচরণ পর্যবেক্ষণ করা হয়। যদিও এই প্রাথমিক ফলাফলগুলো সহায়ক, তবুও এগুলো একটি অসম্পূর্ণ চিত্রই তুলে ধরে এবং Compose ব্যবহারের ক্ষেত্রে ভ্রান্ত নেতিবাচক ধারণা তৈরি করে, কারণ:

  • এটি প্রতিনিধিত্বমূলক নয় — একটি স্থানান্তরিত UI কম্পোনেন্ট কোনো নির্দিষ্ট স্ক্রিনে তার সামগ্রিক পারফরম্যান্স সম্পর্কে দরকারি তথ্য দিতে পারে। তবে, বিভিন্ন কম্পোনেন্ট ভিন্ন ভিন্ন কারণে ভিন্নভাবে আচরণ করে, যেগুলোকে সাধারণীকরণ করা যায় না, তাই এর থেকে সবসময় কোনো সিদ্ধান্তে আসা যায় না।
  • ইন্টারঅপারেশন খরচ — একটি বড় ভিউ কোডবেসের মধ্যে থাকা একটি ছোট কম্পোজ কোড দুটি সিস্টেমের মধ্যে সংযোগ স্থাপনের জন্য একটি অপ্রত্যাশিত খরচ বহন করে। এই অতিরিক্ত খরচ পরিমাপকে বিকৃত করে, ফলে প্রাথমিক ছোট আকারের ফলাফলগুলো পূর্ণাঙ্গ মাইগ্রেশনের প্রকৃত চিত্র তুলে ধরে না।

এর ফলস্বরূপ, ছোটখাটো মাইগ্রেশনগুলো কার্যকরী হলেও, সবসময় কম্পোজ-এর সম্পূর্ণ প্রভাব প্রতিফলিত করে না। কোনো বাধা দূর করে একটি সারফেসের যত বেশি অংশ শুরু থেকে শেষ পর্যন্ত মাইগ্রেট করা হয়, পারফরম্যান্সের দিক থেকে চিত্রটি তত স্পষ্ট ও উন্নত হয়।

ইনস্টাগ্রাম ডিরেক্ট-এর মূল স্ক্রিনগুলো বিভিন্ন ধরনের আইটেমের দীর্ঘ তালিকাকে কেন্দ্র করে নির্মিত, যা মূলত RecyclerView দিয়ে প্রয়োগ করা হয়েছিল। এই আর্কিটেকচারটি স্কেলেবিলিটির জন্য কাস্টম অ্যাবস্ট্রাকশনের উপর নির্ভর করে, কিন্তু এটি ভিউ-ভিত্তিক সিস্টেমের লাইফসাইকেলের সাথেই আবদ্ধ থাকে।

ডায়াগ্রাম 1.png

দলটির প্রধান কাজ ছিল বিদ্যমান RecyclerView ভিত্তিক আর্কিটেকচারের মধ্যে কয়েকশ স্বতন্ত্র লিস্ট আইটেমকে পর্যায়ক্রমে Compose-এ স্থানান্তর করা এবং A/B টেস্টের অধীনে ছোট ছোট স্বাধীন দলে সেগুলোকে প্রোডাকশনে চালু করা—এই পুরো কাজটিই করা হয়েছিল ব্যবহারকারীর মেসেজিং অভিজ্ঞতায় কোনো দৃশ্যমান পরিবর্তন না এনে।

এই ধরনের সেটআপের সবচেয়ে বড় অসুবিধা হলো, প্রতিটি লিস্ট আইটেমকে Compose-এ সম্পূর্ণরূপে মাইগ্রেট করার পরেও, কোর RecyclerView আর্কিটেকচারের মাধ্যমে লিগ্যাসি ভিউ সিস্টেমের উপর এর উল্লেখযোগ্য নির্ভরশীলতা থেকে যায়। পরবর্তী স্বাভাবিক পদক্ষেপ হিসেবে, টিম RecyclerView ভিত্তিক কোর আর্কিটেকচারটিকে Compose-এর নিজস্ব বিকল্প— LazyColumn দিয়ে প্রতিস্থাপন করার জন্য বিনিয়োগ করার সিদ্ধান্ত নেয়।

এর অর্থ হলো, Compose UI কম্পোনেন্টগুলোকে তাদের নিজস্ব ফ্রেমওয়ার্ক থেকে আড়াল করে রাখতে হবে, এবং একই সাথে RecyclerView ও LazyColumn উভয়ের সাথেই সামঞ্জস্যপূর্ণ হতে হবে। একইভাবে গুরুত্বপূর্ণ হলো, A/B টেস্টিং সক্ষম করার জন্য ফিচার ফ্ল্যাগের মাধ্যমে রানটাইমে এই দুটির মধ্যে পরিবর্তন করার ক্ষমতা।

ডায়াগ্রাম 2.png

যদিও নতুন কম্পোজ আইটেমগুলো স্বাভাবিকভাবেই LazyColumn সাথে সামঞ্জস্যপূর্ণ এবং একটি নিরবচ্ছিন্ন কম্পোজিশন ট্রিতে যুক্ত করা যায়, তবুও সেগুলোকে RecyclerView ব্যবহারের জন্য একটি ইন্টারঅপ এপিআই তৈরি করা হয়েছে। এর ফলে, ফিচার তৈরি ও পরিমার্জনে নিয়োজিত দলের বাকি সদস্যদের কাজে ব্যাঘাত না ঘটিয়ে, একই কম্পোজ আইটেমগুলো পুনঃব্যবহার করে এবং পারফরম্যান্স উন্নত করে, RecyclerView পাশাপাশি একটি এ/বি টেস্টের অধীনে LazyColumn সেটআপটি চালু করা সম্ভব হয়েছে।

ইনস্টাগ্রামের ব্যাপকতা, জটিলতা এবং এমনকি ক্ষুদ্রতম রিগ্রেশনের প্রতি এর সংবেদনশীলতা জেটপ্যাক কম্পোজের জন্য একটি অনন্য চ্যালেঞ্জ তৈরি করেছিল। এগুলোর মোকাবিলা করার জন্য একটি পুনরাবৃত্তিমূলক ও হাতে-কলমে অংশীদারিত্বের প্রয়োজন ছিল। ঘনিষ্ঠভাবে একসাথে কাজ করে, গুগল এবং মেটার ইঞ্জিনিয়াররা ভিউ-ভিত্তিক বেঞ্চমার্কগুলো পূরণ করতে বা অতিক্রম করতে নতুন কম্পোজ সক্ষমতাগুলো চিহ্নিত ও ডিজাইন করার জন্য মেট্রিক্স বিশ্লেষণ করেছেন। এই অংশীদারিত্বের ফলস্বরূপ, জেটপ্যাক কম্পোজে নিম্নলিখিত সংযোজনগুলো বিশেষভাবে উল্লেখযোগ্য: LazyLayoutCacheWindows এবং ভিজিবিলিটি ট্র্যাকিং সহ পজযোগ্য কম্পোজিশন।

LazyLayoutCacheWindows ব্যবহার করে পজযোগ্য কম্পোজিশন

পজেবল কম্পোজিশন (যা কম্পোজ ১.১০- এ ডিফল্টভাবে সক্রিয় থাকে) ব্যয়বহুল লেজি-লিস্ট আইটেমগুলোকে ফ্রেম জুড়ে ধাপে ধাপে সাজিয়ে জ্যাঙ্ক প্রতিরোধ করতে সাহায্য করে। যখন এটি লেজি লেআউট ক্যাশ উইন্ডো (যা কম্পোজ ১.৯- এ যোগ করা হয়েছিল)-এর সাথে যুক্ত করা হয়, তখন এই সংমিশ্রণটি স্ক্রলের মসৃণতা উল্লেখযোগ্যভাবে উন্নত করে। মেটা-তে সাম্প্রতিক অভ্যন্তরীণ পরীক্ষায়, পজেবল কম্পোজিশনকে একটি এক-ভিউপোর্ট LazyLayoutCacheWindow সাথে একত্রিত করলে, সাধারণ কম্পোজের তুলনায় প্রতি মিনিটে বড় ফ্রেম ড্রপ (LFDs/m) প্রায় ১৩% কমে যায়। একই বেসলাইনের তুলনায় শুধুমাত্র ক্যাশ উইন্ডো এটি প্রায় ৮% কমিয়েছিল। LFDs/m হলো একটি অভ্যন্তরীণ মেট্রিক যা মেটা স্ক্রল করার সময় লক্ষণীয় স্টাটার ট্র্যাক করতে ব্যবহার করে।

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 পরিমাণ কন্টেন্ট রাখে।
  • ফ্লোট : ভিউপোর্টের একটি ভগ্নাংশ। aheadFraction = 0.5f স্ক্রিনের অর্ধেক অংশকে সামনে রাখে, তাই এর পরম পরিমাণ স্ক্রিনের উচ্চতার সাথে সামঞ্জস্যপূর্ণ হয় এবং বিভিন্ন ফর্ম ফ্যাক্টরকে সমর্থন করে: ট্যাবলেট বা খোলা ফোল্ডেবল ফোনে বেশি, এবং কমপ্যাক্ট ফোনে কম।

ইনস্টাগ্রাম টিম বিশেষভাবে ডিরেক্ট-এর কন্টেন্ট স্ট্রাকচার এবং আইটেমের আকারের জন্য ক্যাশ উইন্ডোর ফ্লোট ফ্র্যাকশনগুলো সূক্ষ্মভাবে সমন্বয় করেছে। যেহেতু নির্দিষ্ট UI প্যারামিটারের ওপর নির্ভর করে আদর্শ মানগুলো পরিবর্তিত হয়, তাই সঠিক ভারসাম্য খুঁজে পেতে কিছুটা পরীক্ষা-নিরীক্ষার প্রয়োজন হয়।

onVisibilityChanged-এর সাথে ইম্প্রেশন লগিং


দ্য   onVisibilityChanged   (Compose 1.9.0-এ যুক্ত) এপিআই (API) ছিল গুগল এবং মেটার মধ্যকার প্রযুক্তিগত অংশীদারিত্বের আরেকটি গুরুত্বপূর্ণ ফলাফল। এটি বৃহৎ আকারের জেটপ্যাক কম্পোজ সারফেসগুলোকে একটি সামঞ্জস্যপূর্ণ উপায় দেয়, যার মাধ্যমে জানা যায় কখন একটি কম্পোজেবল এলিমেন্ট স্ক্রিনে দৃশ্যমান হচ্ছে। এর ফলে অতীতে ব্যবহৃত কাস্টম, হাতে তৈরি ইমপ্লিমেন্টেশনগুলো প্রতিস্থাপিত হয়েছে। শুধুমাত্র ইনস্টাগ্রাম ডিরেক্টেই, এই ভিজিবিলিটি সিগন্যালগুলো শত শত ফাইল জুড়ে ব্যবহৃত হয় প্রোডাক্ট কোয়ালিটি মেট্রিক্সকে সমর্থন করার জন্য, যা নির্ভর করে ইউআই এলিমেন্টগুলো ব্যবহারকারীদের কাছে আসলেই প্রদর্শিত হয়েছে কি না তার উপর।

স্টার্টআপ পারফরম্যান্স

ইনস্টাগ্রাম ডিরেক্টে জেটপ্যাক কম্পোজ ব্যবহারের ফলে অ্যাপটির অন্যান্য প্ল্যাটফর্মে অপ্রত্যাশিত পারফরম্যান্সের উন্নতি দেখা গেছে। জেটপ্যাক কম্পোজ রানটাইমের একটি ওয়ার্মআপ খরচ আছে যা আপনাকে কেবল একবারই দিতে হয়, এবং যেহেতু মেসেজিং একটি হাই-ট্র্যাফিক প্ল্যাটফর্ম যা ব্যবহারকারীর সেশনের শুরুতেই প্রায়শই ব্যবহার করা হয়, তাই ইনস্টাগ্রামের অন্যান্য প্ল্যাটফর্ম, যেগুলো কম্পোজের ওপর নির্ভরশীল, সেগুলোতেও লক্ষণীয় পারফরম্যান্সের উন্নতি দেখা গেছে।

ইনস্টাগ্রাম ডিরেক্ট-এর ভেতরেই কম্পোজ UI-এর স্টার্টআপ পারফরম্যান্স বেসলাইন প্রোফাইল ব্যবহারের মাধ্যমে অপ্টিমাইজ করা হয়েছিল, যা ইনস্টলের সময় হট কোড পাথগুলোকে প্রি-কম্পাইল করে, ফলে কম্পোজ একদম প্রথমবার চালু থেকেই দ্রুত রেন্ডার হয়।

ইনস্টাগ্রাম ডিরেক্ট থেকে জেটপ্যাক কম্পোজে স্থানান্তরের অভিজ্ঞতা থেকে প্রাপ্ত শিক্ষা 

  • জেটপ্যাক কম্পোজে বিনিয়োগের তাৎক্ষণিক সুফল পাওয়া যায়: কম্পোজের সুবিধা পেতে আপনাকে উন্নত এআই ওয়ার্কফ্লো ব্যবহার করতে হবে না। কোড প্রায় ৫০% কমে যাওয়ায়, রক্ষণাবেক্ষণের জন্য কম কোড থাকে এবং বাগ হওয়ার সম্ভাবনাও কমে যায়।
  • এআই-নেটিভ আর্কিটেকচার ডিজাইন করার ফলে উল্লেখযোগ্য সাফল্য অর্জিত হয়েছে , যার মধ্যে রয়েছে এআই এজেন্টের কার্য সম্পাদনের সময় ৩৫% হ্রাস, ইঞ্জিনিয়ার-এজেন্ট বিনিময় ৩২% হ্রাস এবং টোকেন খরচ ৩৩% হ্রাস।
  • যদিও ভিউ এবং কম্পোজকে একত্রিত করার জন্য প্রচুর ইন্টারঅপ এপিআই এবং সাপোর্ট রয়েছে, তবুও স্বতন্ত্র ছোট কম্পোনেন্টের পরিবর্তে বড় সারফেসগুলোকে মাইগ্রেট করার লক্ষ্য রাখুন । এটি ইউআই-কে একটি একক, নিরবচ্ছিন্ন কম্পোজিশন হায়ারার্কির মধ্যে রাখে এবং কম্পোজের নিজস্ব সেরা পারফরম্যান্স অপটিমাইজেশনগুলোর সব সুবিধা উন্মোচন করে।
  • Pausable composition-এর সাথে LazyLayoutCacheWindow-কে যুক্ত করুন : এই দুটিকে একসাথে ব্যবহার করলে শুধু ক্যাশ উইন্ডোর চেয়ে ভালো ফলাফল পাওয়া যায়। শুধুমাত্র ক্যাশ উইন্ডো ব্যবহার করলে, একটি ভারী আইটেম একবারে কম্পোজ হওয়ার চেষ্টা করতে পারে, যা ফ্রেম বাজেট অতিক্রম করার সম্ভাবনা তৈরি করে।
  • Compose-এর উন্নয়নে অবদান রাখুন! Meta, Jetpack Compose টিমের সাথে অংশীদারিত্ব করেছে তাদের মতামত ও ধারণাগুলোকে Compose-এর মধ্যে বাস্তবায়িত করার জন্য। একটি ওপেন-সোর্স টুলকিটে কাজ করার অর্থ হলো, যখন বাগ এবং পারফরম্যান্সের উন্নতিগুলো কেন্দ্রীয়ভাবে করা হয়, তখন আমরা সবাই উপকৃত হই। তাই, আপনার মতামত জানান!

জেটপ্যাক কম্পোজ গ্রহণ করার ফলে এআই-সহায়তাযুক্ত ডেভেলপমেন্টে উল্লেখযোগ্য অগ্রগতি সাধিত হয়েছে এবং একই সাথে ইনস্টাগ্রামে দৈনন্দিন UI ইঞ্জিনিয়ারিংয়ের কাজও সহজ হয়েছে। এই ডিক্লারেটিভ পদ্ধতিটি গতানুগতিক কোড কমায়, স্টেট সম্পর্কে ধারণা লাভ করা সহজ করে এবং ডেভেলপারদের সার্বিক উৎপাদনশীলতা বাড়ায়। ইনস্টাগ্রাম ইঞ্জিনিয়ারিং টিম অ্যাপের আরও বিভিন্ন প্ল্যাটফর্মে কম্পোজ নিয়ে আসার জন্য উন্মুখ হয়ে আছে এবং গুগল ও মেটার মধ্যে চলমান সহযোগিতার মাধ্যমে ইনস্টাগ্রাম ও জেটপ্যাক কম্পোজ ব্যবহারকারী উভয়ের জন্যই আরও উন্নতি নিয়ে আসতে আগ্রহী।

আপনি যদি এখনও Compose ব্যবহার করে না থাকেন, তবে এখন AI-সহায়তা সহ Jetpack Compose-এ স্থানান্তরিত হওয়া আগের চেয়েও সহজ।

কৃতজ্ঞতা জ্ঞাপন। মেটা এবং গুগলের যৌথ উদ্যোগে কম্পোজ-এর কর্মক্ষমতা উন্নত করার জন্য মেটা-র মাইকেল জিলিনস্কি ও ম্যাথিউ ডু এবং গুগল-এর আন্দ্রেই শিকভ ও জর্জ মাউন্টকে ধন্যবাদ! এছাড়াও, ইনস্টাগ্রাম ডিরেক্ট-এ কম্পোজ নিয়ে আসতে সাহায্য করার জন্য মেটা-র গ্যারি ইয়ে-কে এবং ডেটা সায়েন্সের মাধ্যমে এই প্রচেষ্টাকে সমর্থন করার জন্য মেটা-র গোপাল জুনেজাকে ধন্যবাদ!

লিখেছেন:
পড়তে থাকুন