Cara engineer Instagram Direct membangun arsitektur UI berbasis AI dengan Jetpack Compose dan mengurangi biaya token per sesi agen sebesar 33%
Waktu baca: 11 menit
Postingan blog ini ditulis melalui kolaborasi dengan tim Meta
Instagram Direct adalah salah satu platform inti di Instagram, yang menangani miliaran pesan pengguna setiap hari. Selama bertahun-tahun melakukan iterasi, tim ini telah memaksimalkan setiap pengoptimalan mikro dari sistem View Android lama. Namun, mempertahankan dan memperluas platform lama yang sangat dioptimalkan akan menimbulkan utang teknis dan overhead engineering yang signifikan, terutama karena tim makin banyak mengadopsi UI deklaratif dan asisten coding AI.
Penerapan Jetpack Compose untuk Instagram Direct tidak hanya sekadar modernisasi UI biasa. Tim ini membangun codebase UI berbasis AI yang 50% lebih kecil daripada implementasi aslinya, sekaligus mencapai pengurangan waktu eksekusi agen AI sebesar 35% , pengurangan interaksi engineer-agen sebesar 32% , dan pengurangan biaya token sebesar 33% . Melalui kemitraan yang erat dengan Google, tim ini mengadopsi Jetpack Compose sekaligus mempertahankan standar performa yang tinggi. Melalui pengoptimalan performa, Meta dan Google meningkatkan Compose tidak hanya untuk Instagram, tetapi juga untuk ekosistem developer Android yang lebih luas.
Memodernisasi codebase dalam skala besar
AI telah dengan cepat menjadi pendamping harian bagi engineer di industri, dan menerapkannya ke codebase berskala besar seperti Instagram telah memberikan peningkatan produktivitas yang nyata. Tim Instagram Direct menetapkan sasaran yang lebih ambisius. Alih-alih sekadar mengarahkan alat AI ke kode yang ada, tim mendesain ulang codebase dan arsitekturnya agar menjadi AI-native, sehingga melipatgandakan dampak AI jauh melampaui apa yang dapat diberikan oleh retrofit saja.
Tim Instagram Direct memilih Jetpack Compose sebagai komponen utama untuk membangun arsitektur UI native AI. Sifat deklaratifnya memastikan kode ringkas, dapat diprediksi, dan secara struktural lebih mudah dipahami oleh model AI, dengan lebih sedikit efek samping, status yang tidak terlalu implisit, dan batas komponen yang lebih jelas.
Migrasi ke Jetpack Compose memerlukan perencanaan yang cermat. Ratusan juta orang mengirim pesan di Instagram setiap hari, sehingga migrasi harus dilakukan secara bertahap, lancar, dan tanpa gangguan pada pengalaman pengguna saat tim merancang ulang fondasi di baliknya. Untuk menggambarkan skala tantangannya: Komponen UI individual dapat dirender dalam lebih dari 160 permutasi status yang berbeda, dan satu layar percakapan saja menangani lebih dari 200 jenis pesan yang berbeda.
Saat memigrasikan codebase sebesar ini ke Compose, Anda mungkin tergoda untuk mengambil jalan pintas dan menyematkan komponen UI Compose di dalam hierarki View yang ada. Sebagai langkah inkremental selama migrasi bertahap, hal ini sepenuhnya valid. Namun, dalam jangka panjang, mengintegrasikan Compose di dalam codebase berbasis View akan menimbulkan tantangan. Alat AI sering kali mengambil jalur yang paling mudah. Jika Anda mencampur kode UI deklaratif dan imperatif, AI kemungkinan akan menggabungkannya secara tidak benar, sehingga menimbulkan bug yang tidak kentara, utang teknis, dan regresi performa.
Membangun arsitektur UI berbasis AI
Dalam skala Instagram, tingkat abstraksi arsitektur tidak dapat dihindari, dan inilah yang membuat aplikasi tetap dapat dikelola seiring pertumbuhannya. Pertimbangkan pola umum, di mana setiap jenis item RecyclerView dimodelkan sebagai turunan dari class dasar RecyclerViewItem kustom yang mengekspos hook siklus proses biasa seperti onBind.
Contoh 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") } } ... } } }
Dalam cuplikan di atas, muncul dua masalah. Pertama, flag isPinnedChatsEnabled dibaca dalam kode imperatif, lalu diambil di dalam lambda Compose, sebuah penggabungan yang halus di seluruh paradigma. Kedua, isPinned berada sebagai kolom yang dapat diubah pada item itu sendiri, bukan di ChatUiState, sehingga bertahan dari pengikatan ulang RecyclerView dan daur ulang di seluruh baris, sehingga menyebabkan kebocoran dan menghasilkan bug yang sulit direproduksi.
Meskipun kode dibersihkan dengan memberikan fungsi @Composable khusus pada item, masalah yang sama tetap ada.
Contoh 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") } } ... } }
Ini adalah contoh sederhana, tetapi menggambarkan masalah yang lebih luas—makin sedikit batasan yang diberikan kepada AI, makin rendah kualitas kode yang dihasilkannya seiring waktu. Pedoman dan keterampilan memang membantu, tetapi tidak cukup jika berdiri sendiri, karena saat AI mengalami hambatan, AI akan sering mencari jalan lain untuk mengatasinya.
Agar codebase menjadi ramah AI, codebase harus mengikuti dua aturan praktis:
- Minimalkan dependensi pada konteks kustom. Makin banyak pengetahuan khusus codebase yang diperlukan agen AI untuk membuat perubahan yang benar, makin rendah kualitas output-nya. Makin dekat codebase dengan praktik terbaik yang diketahui, makin baik hasil AI.
- Codebase yang mengutamakan AI harus menerapkan batasannya sendiri. Menambal celah desain dengan keterampilan AI tidak dapat diskalakan, karena setiap keterampilan yang dimuat ke dalam konteks memerlukan token dan dapat menurunkan performa agen. Sebaliknya, arsitektur itu sendiri yang harus menanggung beban tersebut. Agen AI secara alami mengambil jalur yang paling mudah, sehingga desain harus membuat jalur tersebut mengarah ke kode yang benar dan berkualitas tinggi, sekaligus membuat keputusan desain yang buruk menjadi sulit dan mahal untuk diungkapkan.
Item daftar masih dapat direpresentasikan oleh abstraksinya sendiri, tetapi dalam hal ini semua kode Compose berada di konstruktor, sehingga tidak memiliki akses ke anggota atau status class, dan satu-satunya sumber argumennya adalah konstruktor. Hal ini membuatnya setara dengan fungsi @Composable biasa, sekaligus sesuai dengan arsitektur yang ada.
Contoh 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") } } ... }, )
Memigrasikan codebase sebesar ini adalah pekerjaan yang sangat besar. Selama waktu yang lama, ratusan komponen UI yang membentuk sebagian besar Direct UI harus berdampingan dengan komponen lama, dan keduanya dikelola secara paralel. Alur kerja AI membantu memungkinkan migrasi paralel ini dengan mempercepat proses penulisan kode dalam jumlah besar. Pendekatan tersebut memungkinkan tim Direct melakukan migrasi dalam waktu singkat, tanpa mengganggu anggota tim lainnya, yang terus meluncurkan fitur untuk meningkatkan pengalaman jutaan orang setiap hari.
Beberapa engineer menjalankan agen AI mereka sendiri terhadap pusat informasi bersama yang berisi keterampilan dan konvensi yang dapat digunakan kembali yang dibuat selama migrasi. Hal ini membuat alur kerja dan praktik terbaik tetap sinkron di seluruh tim, sehingga setiap engineer tidak perlu menemukannya kembali. Dalam setiap platform, tim melakukan migrasi dalam tahap-tahap berikut:
- Tulis semua kode Compose dengan AI.
- Menyempurnakannya, menangani kasus ekstrem, dan menutup kesenjangan performa, hingga UI diluncurkan kepada pengguna sungguhan dalam pengujian publik.
Membagi pekerjaan menjadi dua tahap per layar memungkinkan satu engineer bergerak cepat di seluruh platform, menyelesaikan arsitektur dan kasus ekstrem yang rumit di awal. Dengan dasar tersebut, orang lain dapat berfokus untuk menyiapkan UI agar siap produksi tanpa harus berhenti untuk membuat keputusan teknis sendiri, sehingga keseluruhan migrasi tetap cepat.
Hasil migrasi memvalidasi pendekatan tersebut. Untuk platform Instagram Direct yang dimigrasikan, Jetpack Compose memungkinkan tim mengurangi jumlah total kode UI sebesar 50%. Makin sedikit kode yang harus dibuat AI, makin tinggi kualitas output dan makin rendah biaya token per tugas.
Analisis data internal codebase Android untuk Instagram Direct membandingkan sesi agen AI yang mengerjakan Compose UI dengan tugas yang sama menggunakan Android View. Peningkatan efisiensi terlihat jelas dalam dua dimensi:
- Per karakter kode yang di-deploy: Compose memerlukan 32% lebih sedikit interaksi engineer-agen dan 35% lebih sedikit waktu eksekusi agen (waktu yang berlalu sejak agen mulai mengerjakan permintaan engineer hingga agen memberikan respons).
- Per sesi agen: Biaya token keseluruhan turun sebesar 33% dengan Compose dibandingkan dengan View.
Kami melaporkan efisiensi output dan jumlah sesi standar karena keduanya merupakan hasil yang berguna secara independen. Angka pertukaran engineer-agen dan waktu eksekusi membandingkan penggunaan resource per unit output yang dihasilkan, sedangkan angka token membandingkan total biaya untuk sesi agen standar.
Data tersebut juga mengungkapkan perbedaan yang konsisten dalam cara kedua framework menangani kode yang kompleks atau rentan. Meta melacak hal ini menggunakan skor risiko perubahan kode, yang mengevaluasi kualitas kode secara keseluruhan dan kemungkinan perubahan yang menyebabkan insiden produksi. Analisis ini mengukur efisiensi resource agen menggunakan gabungan konsumsi token, waktu eksekusi agen, dan interaksi engineer dengan agen. Seiring file mengumpulkan skor risiko yang lebih tinggi, sesi agen AI secara alami menjadi kurang efisien dalam penggunaan resource.
Jika skor penilaian risiko akumulatif file meningkat dua kali lipat, UI yang diimplementasikan dengan Android Views akan mengurangi efisiensi resource agen sebesar 30% (per karakter yang ditampilkan). Dalam situasi yang sama, pengurangan oleh UI Jetpack Compose hanya 9%
Melalui kemitraan antara Google dan Meta, tim Instagram Direct menghadirkan perspektif baru dalam adopsi Compose, yaitu mendekatinya melalui lensa kesiapan AI codebase, bukan sekadar penulisan ulang UI. Pekerjaan ini menunjukkan kekuatan Compose dalam berfungsi sebagai fondasi untuk membangun codebase dan arsitektur yang mengutamakan AI, terutama saat diterapkan pada skala aplikasi seperti Instagram.
Pengoptimalan performa
Instagram Direct adalah salah satu platform paling integral di aplikasi ini, dan orang-orang mengharapkannya terasa cepat dan responsif setiap saat. Mengadopsi Jetpack Compose secara efektif berarti penulisan ulang UI yang substansial, dan sasaran utamanya adalah mempertahankan pengalaman berkualitas tinggi tanpa regresi.
Iterasi selama bertahun-tahun telah mendorong implementasi berbasis View lama di Instagram ke standar performa yang sangat tinggi, dan tim perlu memenuhi standar yang sama saat beralih ke framework UI yang sepenuhnya baru.
Instagram mengukur ratusan, bahkan ribuan, metrik performa. Untuk adopsi Compose, tiga hal berikut adalah yang paling penting:
- Waktu untuk berinteraksi - jumlah waktu antara membuka layar hingga dapat menggunakannya.
- Waktu untuk memuat sepenuhnya - jumlah waktu antara membuka layar hingga semua konten dimuat sepenuhnya (misalnya, gambar).
- Performa scroll - seberapa lancar layar di-scroll, tanpa frame yang hilang.
Metrik ini dilacak saat runtime dalam produksi, sehingga memungkinkan untuk menjalankan pengujian A/B yang membandingkan UI Compose yang dimigrasikan dengan UI lama dan mengevaluasi dampak performa dari upaya ini.
Cara umum untuk melakukan migrasi seperti ini adalah dengan memulai dari hal kecil, memindahkan beberapa komponen UI, mengumpulkan data, dan mempelajari perilakunya. Meskipun bermanfaat, hasil awal ini hanya memberikan gambaran parsial, yang memberikan negatif palsu terhadap adopsi Compose karena:
- Tidak representatif — satu komponen UI yang dimigrasikan dapat memberikan data yang berguna tentang performa keseluruhannya di layar tertentu. Namun, komponen yang berbeda berperilaku berbeda karena alasan yang tidak dapat digeneralisasi, sehingga Anda tidak selalu dapat mengekstrapolasi darinya.
- Biaya interop — bagian Compose kecil di dalam codebase View besar membayar biaya penghubung yang tidak dapat diprediksi antara kedua sistem. Overhead tersebut mendistorsi pengukuran, sehingga hasil awal berskala kecil tidak mencerminkan tampilan migrasi penuh yang sebenarnya.
Hasilnya, migrasi kecil, meskipun berguna, tidak selalu mencerminkan dampak penuh Compose. Semakin banyak platform yang dimigrasikan secara menyeluruh tanpa gangguan bridging, semakin jelas dan baik gambaran performanya.
Layar inti di Instagram Direct dibuat berdasarkan daftar panjang berbagai jenis item, yang awalnya diimplementasikan dengan RecyclerView. Arsitektur ini mengandalkan abstraksi kustom untuk skalabilitas, tetapi tetap terikat dengan siklus proses sistem berbasis View.
Tugas utama tim adalah migrasi bertahap beberapa ratus item daftar individual ke Compose dalam arsitektur berbasis RecyclerView yang ada, meluncurkannya dalam produksi dalam grup independen kecil di bawah pengujian A/B — semuanya tanpa perubahan yang terlihat pada pengalaman pesan pengguna.
Kelemahan terbesar dari penyiapan tersebut adalah dependensi yang signifikan pada sistem View lama melalui arsitektur RecyclerView inti, bahkan setelah migrasi penuh setiap item daftar ke Compose. Sebagai langkah alami berikutnya, tim memutuskan untuk berinvestasi dalam mengganti arsitektur inti berbasis RecyclerView dengan alternatif native Compose — LazyColumn.
Artinya, komponen Compose UI harus diabstraksi dari framework yang menyertainya, sekaligus tetap kompatibel dengan RecyclerView dan LazyColumn secara bersamaan. Hal yang sama pentingnya adalah kemampuan untuk beralih di antara keduanya saat runtime melalui tombol fitur, untuk mengaktifkan pengujian A/B.
Meskipun item Compose baru kompatibel secara native dengan LazyColumn dan dapat dicolokkan ke hierarki komposisi tanpa gangguan, API interop dibuat untuk memasukkannya ke RecyclerView juga. Hal ini memungkinkan peluncuran penyiapan LazyColumn dalam pengujian A/B secara berdampingan dengan RecyclerView — menggunakan kembali item Compose yang sama dan meningkatkan performa, tanpa mengganggu anggota tim lainnya yang sedang membangun dan menyempurnakan fitur.
Skala, kompleksitas, dan sensitivitas Instagram terhadap regresi terkecil sekalipun menimbulkan tantangan unik bagi Jetpack Compose. Untuk mengatasinya, diperlukan kemitraan praktis yang berulang. Dengan bekerja sama secara erat, engineer Google dan Meta menganalisis metrik untuk menentukan dan mendesain kemampuan Compose baru guna memenuhi atau melampaui tolok ukur berbasis View. Sebagai hasil dari kemitraan ini, penambahan berikut pada Jetpack Compose menjadi sangat penting: Komposisi yang dapat dijeda dengan LazyLayoutCacheWindows dan pelacakan visibilitas.
Komposisi yang dapat dijeda dengan LazyLayoutCacheWindows
Komposisi yang dapat dijeda (diaktifkan secara default di Compose 1.10) memungkinkan item daftar lambat yang mahal dikomposisi secara inkremental di seluruh frame untuk mencegah jank. Jika dipasangkan dengan LazyLayoutCacheWindow (ditambahkan di Compose 1.9), kombinasi ini akan meningkatkan kelancaran scroll secara signifikan. Dalam pengujian internal terbaru di Meta, menggabungkan komposisi Pausable dengan LazyLayoutCacheWindow satu area pandang mengurangi penurunan frame besar per menit (LFD/m) sekitar 13% dibandingkan dengan Compose standar. Cache Window sendiri menguranginya sekitar 8% terhadap dasar pengukuran yang sama. LFD/m adalah metrik internal yang digunakan Meta untuk melacak stutter yang terlihat saat men-scroll.
Menggunakan LazyLayoutCacheWindow di aplikasi Anda akan menyiapkan dan mempertahankan item di luar layar dalam band berbasis piksel di sekitar area pandang untuk memungkinkan fling cepat. Untuk memanfaatkan LazyLayoutCacheWindows di aplikasi, Anda dapat menggunakan Compose 1.13.0-alpha03 terbaru dan menyiapkannya seperti yang ditunjukkan dalam contoh di bawah:
val cacheWindow = LazyLayoutCacheWindow(ahead = 150.dp, behind = 100.dp) // OR val cacheWindow = LazyLayoutCacheWindow(aheadFraction = 0.5f, behindFraction = 0.3f) LazyColumn(state = state, cacheWindow = cacheWindow) { ... }
Ada dua cara untuk mengonfigurasi periode cache. Keduanya menjelaskan hal yang sama: jumlah konten di luar layar yang akan tetap disusun, tetapi dalam unit yang berbeda.
- Dp: panjang absolut tetap.
ahead = 150.dpmempertahankan konten 150 dp yang disusun melewati tepi yang terlihat, apa pun perangkatnya. - Float: pecahan area pandang.
aheadFraction = 0.5fmempertahankan setengah layar yang disusun di depan, sehingga jumlah absolutnya diskalakan dengan tinggi layar yang mendukung berbagai faktor bentuk: lebih banyak di tablet atau perangkat foldable yang dibentangkan, lebih sedikit di ponsel yang ringkas.
Tim Instagram menyesuaikan pecahan float jendela cache secara khusus untuk struktur konten dan ukuran item Direct. Karena nilai ideal bervariasi bergantung pada parameter UI tertentu, menemukan keseimbangan yang tepat memerlukan beberapa eksperimen.
Logging tayangan iklan dengan onVisibilityChanged
API onVisibilityChanged (ditambahkan di Compose 1.9.0) adalah hasil penting lainnya dari kemitraan teknis antara Google dan Meta. Library ini memberi platform Jetpack Compose berskala besar cara yang konsisten untuk mengetahui kapan composable benar-benar terlihat di layar, menggantikan implementasi kustom yang dibuat secara manual yang digunakan sebelumnya. Di Instagram Direct saja, sinyal visibilitas ini digunakan di ratusan file untuk mendukung metrik kualitas produk yang bergantung pada apakah elemen UI benar-benar ditampilkan kepada orang-orang.
Performa startup
Penerapan Jetpack Compose untuk Instagram Direct menghasilkan peningkatan performa yang tidak terduga di berbagai platform aplikasi lainnya. Runtime Jetpack Compose memiliki biaya pemanasan yang hanya Anda bayar sekali, dan karena pesan adalah platform dengan traffic tinggi yang sering dikunjungi di awal sesi pengguna, platform lain di Instagram yang mengandalkan Compose mengalami peningkatan performa yang signifikan.
Performa startup Compose UI di dalam Instagram Direct sendiri dioptimalkan menggunakan Profil Dasar Pengukuran, yang melakukan pra-kompilasi jalur kode panas pada waktu penginstalan sehingga Compose merender dengan cepat sejak peluncuran pertama.
Pelajaran dari migrasi Instagram Direct ke Jetpack Compose
- Jetpack Compose memberikan laba atas investasi yang cepat: Anda tidak perlu menggunakan alur kerja AI tingkat lanjut untuk mendapatkan manfaat dari Compose. Dengan pengurangan kode sekitar 50%, berarti lebih sedikit kode yang harus dikelola, dan mengurangi area permukaan untuk bug.
- Mendesain arsitektur berbasis AI menghasilkan pencapaian yang signifikan, termasuk pengurangan waktu eksekusi agen AI sebesar 35%, pengurangan interaksi engineer-agen sebesar 32%, dan pengurangan biaya token sebesar 33%.
- Meskipun ada banyak API interop dan dukungan untuk menggabungkan View dan Compose, usahakan untuk memigrasikan platform yang lebih besar daripada komponen kecil satu per satu. Hal ini menjaga UI dalam satu hierarki komposisi yang tidak terputus dan mengaktifkan semua pengoptimalan performa native Compose terbaik.
- Gabungkan composable Pausable dengan LazyLayoutCacheWindow: Menggabungkan keduanya akan memberikan hasil yang lebih baik daripada hanya menggunakan jendela cache. Hanya dengan jendela cache, item yang berat masih dapat mencoba membuat dalam satu penerusan, yang berpotensi melebihi anggaran frame.
- Berkontribusi pada Compose itu sendiri. Meta telah berpartner dengan tim Jetpack Compose untuk mewujudkan masukan dan ide mereka dalam Compose. Dengan menggunakan toolkit open source, kita semua akan mendapatkan manfaat saat bug dan peningkatan performa dilakukan secara terpusat. Jadi, sampaikan masukan Anda.
Mengadopsi Jetpack Compose memberikan keuntungan signifikan dalam pengembangan yang didukung AI sekaligus menyederhanakan rekayasa UI sehari-hari di Instagram. Pendekatan deklaratif mengurangi boilerplate, mempermudah pemahaman status, dan meningkatkan produktivitas developer secara keseluruhan. Tim engineering Instagram berharap dapat menghadirkan Compose ke lebih banyak platform di seluruh aplikasi, dan melanjutkan kolaborasi antara Google dan Meta untuk menghadirkan lebih banyak peningkatan bagi pengguna Instagram dan Jetpack Compose.
Jika Anda belum mencoba Compose, kini dengan bantuan AI, bermigrasi ke Jetpack Compose menjadi lebih mudah dari sebelumnya.
Ucapan terima kasih. Terima kasih kepada Michal Zielinski dan Matthew Du dari Meta, serta Andrei Shikov dan George Mount dari Google, atas upaya mereka dalam meningkatkan performa Compose melalui kolaborasi antara Meta dan Google. Terima kasih juga kepada Gary Ye dari Meta yang telah membantu menghadirkan Compose ke Instagram Direct, dan kepada Gopal Juneja dari Meta yang telah mendukung upaya ini melalui data science.
-
Studi KasusGrab adalah aplikasi super terkemuka di Asia Tenggara, yang menawarkan layanan pengiriman, mobilitas, dan keuangan kepada jutaan pengguna di delapan negara melalui satu aplikasi.
Ajesh Pai, Nguyen Van Minh, Tracy Agyemang • Waktu baca: 5 menit -
Studi KasusWhatsApp adalah platform pesan terbesar di dunia, yang melayani miliaran pengguna di seluruh dunia. WhatsApp adalah alat komunikasi default bagi orang-orang di berbagai wilayah, yang menghubungkan pengguna melalui pesan pribadi, andal, dan aman.
Niharika Arora, Tracy Agyemang, Mayank Jain • Waktu baca: 8 menit -
Studi KasusTinder memiliki misi untuk mendukung dan menginspirasi koneksi nyata dengan membuat pertemuan menjadi mudah dan menyenangkan bagi setiap generasi lajang baru.
Ajesh Pai, Ulises Uriel Verduzco Díaz , Tracy Agyemang • Waktu baca: 4 menit
Dapatkan insight pengembangan Android terbaru yang dikirim ke kotak masuk Anda setiap minggu.