Bagaimana Browser untuk iOS meningkatkan pengujian A / B. Laporan Yandex

Belum lama ini, kami melihat bagaimana eksperimen A / B dalam Pencarian diatur. Kepala tim pengembangan untuk versi iOS Yandex.Browser Andrei Sikerin sav42 pada pertemuan terakhir CocoaHeads Rusia juga berbicara tentang infrastruktur pengujian A / B, hanya dalam proyeknya.



- Hai, nama saya Andrey Sikerin, saya sedang mengembangkan Yandex.Browser untuk iOS. Saya ingin memberi tahu Anda apa platform percobaan browser untuk iOS, bagaimana kami belajar menggunakannya, mendukung fitur-fiturnya yang lebih canggih, cara mendiagnosis dan men-debug fitur yang diluncurkan menggunakan sistem eksperimen, dan juga apa sumber entropi dan di mana koin disimpan.

Jadi mari kita mulai. Kami di Browser untuk iOS tidak pernah menggulirkan fitur ke pengguna sekaligus. Pertama, kami melakukan pengujian A / B, menganalisis metrik produk dan teknis untuk memahami bagaimana fitur yang digulung mempengaruhi pengguna, apakah ia suka atau tidak, apakah itu menyia-nyiakan beberapa metrik teknis. Untuk ini kami menggunakan analitik. Analitik kami terlihat seperti ini:



Ada sekitar 85 metrik. Kami membandingkan beberapa grup pengguna. Misalkan ini meningkatkan metrik kami - misalnya, kemampuan produk untuk mempertahankan pengguna (retensi) β€”dan tidak menyia-nyiakan orang lain yang tidak ada di slide. Ini berarti bahwa pengguna menyukai fitur dan dapat digulirkan ke sekelompok besar pengguna.

Namun, jika kita menghambur-hamburkan sesuatu, maka kita mengerti sebabnya. Kami membangun hipotesis, mengonfirmasikannya. Jika kami menggambar metrik teknis - ini adalah pemblokir. Kami memperbaikinya dan menjalankan kembali percobaan lagi. Dan sampai kita melukis semuanya. Jadi, kami meluncurkan fitur yang bukan sumber regresi.

Mari kita bicara tentang sistem eksperimen asli yang kami gunakan. Dia sudah cukup berkembang. Maka saya akan memberi tahu Anda apa yang tidak cocok dengan kami.



Pertama, ini didasarkan pada sistem percobaan Chromium dan tidak sepenuhnya didukung di iOS. Kedua, ini awalnya dapat meluncurkan fitur ke grup pengguna yang berbeda dan memiliki sistem filter yang memungkinkan untuk menetapkan persyaratan untuk perangkat. Yaitu - versi aplikasi dari mana fitur tersebut tersedia, lokal perangkat - misalkan kita ingin eksperimen hanya untuk lokal Rusia. Baik versi iOS di mana fitur ini akan tersedia, atau tanggal di mana eksperimen ini akan valid - misalnya, jika kita ingin melakukan eksperimen hanya sampai tanggal tertentu. Secara umum, ada banyak tag dan itu cukup nyaman.

Sistem eksperimen itu sendiri terdiri dari file yang berisi deskripsi konfigurasi percobaan. Artinya, untuk satu percobaan dapat ada beberapa konfigurasi sekaligus. File ini adalah file teks, ini dikompilasi menjadi protobuf dan diletakkan di server.

Setiap konfigurasi terdiri dari grup. Ada percobaan, ia memiliki beberapa konfigurasi, dan di masing-masingnya ada beberapa kelompok. Fitur dalam kode terlampir pada nama grup aktif dari konfigurasi aktif. Ini mungkin terlihat cukup rumit, tetapi sekarang saya akan menjelaskan secara terperinci apa itu.



Bagaimana cara kerjanya secara teknis? File dengan deskripsi semua konfigurasi diunggah ke server. Saat startup, itu diunduh oleh browser dari server dan disimpan ke disk. Lain kali kita mulai, kita mendekode file ini pertama kali dalam rantai inisialisasi aplikasi. Dan untuk setiap percobaan unik kami menemukan satu konfigurasi yang akan aktif.

Konfigurasi yang sesuai untuk kondisi yang ditentukan dan dijelaskan di dalamnya dapat menjadi aktif. Jika ada beberapa konfigurasi aktif yang sesuai dengan kondisi yang ditentukan, maka konfigurasi yang akan lebih tinggi dalam file diaktifkan.

Lebih jauh dalam konfigurasi aktif, koin dilemparkan. Koin dilemparkan secara lokal, dan menurut koin ini dengan cara tertentu, yang akan saya bahas nanti, kelompok aktif percobaan dipilih. Dan tepat sesuai dengan nama grup aktif percobaan yang kami lampirkan dalam kode, memeriksa apakah fitur kami tersedia atau tidak.

Fitur utama dari sistem ini adalah tidak menyimpan apa pun dengan sendirinya. Artinya, dia tidak memiliki penyimpanan apa pun pada disk. Setiap peluncuran - kami mengambil file, mulai menghitungnya, menemukan konfigurasi aktif. Di dalam konfigurasi, sesuai dengan koin, kami menemukan grup aktif, dan sistem percobaan untuk eksperimen ini mengatakan: grup ini dipilih. Artinya, semuanya dihitung, tidak ada yang disimpan.



Biarkan saya, pada kenyataannya, menunjukkan kepada Anda file dengan deskripsi percobaan. Browser memiliki fitur seperti itu - Penerjemah. Dia melakukan percobaan. File dimulai dengan blok studi. Konfigurasi percobaan apa pun dimulai dengan blok ini. Percobaan ini disebut penerjemah. Mungkin ada beberapa blok studi seperti itu dengan nama ini. Dan di dalam blok studi, ada banyak blok percobaan yang diberi nama berbeda. Dalam hal ini, kami melihat grup eksperimen diaktifkan. Dan ada blok filter, yang, pada kenyataannya, menjelaskan dalam kondisi apa konfigurasi ini dapat menjadi aktif, yaitu kriteria.

Ada dua tag di sini - saluran dan ya_min_version. Saluran berarti tampilan perakitan. BETA ditunjukkan di sini, yang berarti bahwa konfigurasi dalam file ini dapat menjadi aktif hanya untuk rakitan yang kami kirim ke TestFlight. Untuk pembuatan App Store, konfigurasi dengan kriteria saluran ini tidak dapat menjadi aktif.

ya_min_version berarti bahwa dengan versi minimum aplikasi 19.3.4.43 konfigurasi ini dapat menjadi aktif. Sebenarnya, dalam versi aplikasi ini, fitur tersebut telah memperoleh formulir yang dapat Anda aktifkan.

Ini adalah deskripsi paling sederhana dari grup konfigurasi eksperimen penerjemah. Mungkin ada banyak blok studi seperti itu dalam file. Dengan menggunakan tag di blok filter, kami mengaturnya untuk saluran yang berbeda, untuk rakitan internal, untuk rakitan BETA, untuk berbagai kriteria.

Berikut ini adalah satu grup eksperimen yang disebut diaktifkan, dan memiliki tag bobot probabilitas, bobot grup eksperimen. Ini adalah bilangan bulat non-negatif yang digunakan untuk menentukan grup aktif pada saat koin muncul.

Mari kita bayangkan bahwa konfigurasi pada slide ini telah menjadi aktif. Artinya, kami benar-benar menginstal aplikasi dengan beta publik, dan kami benar-benar memiliki versi 19.3.4.43 dan seterusnya. Bagaimana cara koin dilemparkan? Koin adalah angka acak yang dihasilkan secara lokal dari nol hingga satu.

Sehingga selama peluncuran berikutnya kita termasuk dalam kelompok yang sama, itu disimpan dalam disk. Sementara kami akan mempertimbangkannya. Selanjutnya, saya akan memberi tahu Anda cara memastikan itu tidak disimpan. Koin dibuang. Misalkan 0,5 dibuang. Koin ini diskalakan dalam segmen dari nol hingga jumlah kelompok eksperimen. Dalam hal ini, kami memiliki satu grup yang diaktifkan, bobotnya adalah 1000, yaitu, jumlah semua kelompok akan menjadi 1000. β€œ0,5” skala menjadi 500. Dengan demikian, semua grup eksperimen membagi interval dari nol ke jumlah percobaan dan kesenjangan. Dan grup menjadi aktif dalam interval yang nilai skala dari koin akan menunjukkan.

Kita dapat menanyakan nama grup eksperimen aktif dalam kode dan dengan demikian menentukan aksesibilitas - apakah kita perlu mengaktifkan fitur atau tidak.



Selanjutnya kita akan melihat konfigurasi eksperimental yang lebih kompleks yang kami gunakan dalam produksi. Pertama, jelas bahwa bodoh untuk meluncurkan fitur untuk 100%, kami menggunakan ini hanya untuk beta atau untuk perakitan internal. Untuk produksi, kami menggunakan mekanik berikut.

Kami membagi pengguna menjadi tiga grup - pengguna lama, pengguna tanpa eksperimen dan pengguna baru. Dalam arti, ini berarti yang berikut. Pengguna lama adalah mereka yang telah menggunakan aplikasi kami dan menginstal aplikasi dengan fitur di atas versi lama. Artinya, mereka sudah menggunakannya, mereka tidak memiliki fitur, mereka terbiasa dengan semuanya dan tiba-tiba memperbarui aplikasi, di mana ada semacam eksperimen, fungsionalitas baru. Kemudian - pengguna tanpa eksperimen dan pengguna baru. Yang baru adalah yang membersihkan aplikasi. Artinya, mereka tidak pernah menggunakan Yandex.Browser, mereka tiba-tiba memutuskan untuk menggunakannya dan menginstal aplikasi.

Bagaimana kita mencapai partisi ini? Di blok filter, kami menetapkan kondisi untuk tag min_install_date dan max_install_date. Misalkan X adalah 14 Maret 2019 - ini adalah tanggal rilis untuk pembuatan fitur. Maka max_install_date untuk pengguna lama akan menjadi X minus 21 hari, sebelum rilis perakitan dengan fitur. Jika aplikasi memiliki tanggal pemasangan seperti itu, kemungkinan besar peluncuran pertamanya adalah sebelum rilis. Dan sebelum rilis ada versi tanpa fitur. Dan jika sekarang ia memiliki, secara kondisional, versi dengan fitur, itu berarti ia menerima aplikasi dengan bantuan pembaruan.

Dan untuk pengguna baru, kami menetapkan min_install_date. Kami mengeksposnya sebagai X ditambah beberapa hari. Ini berarti: jika ia memiliki tanggal pemasangan sedemikian, yaitu, ia melakukan peluncuran pertama setelah tanggal rilis versi dengan fitur, maka ia memiliki instalasi yang bersih. Dia sekarang memiliki versi dengan fitur, tetapi tanggal instal lebih lambat dari versi ini dengan fitur.

Karenanya, kami memecah pengguna menjadi yang lama, tanpa eksperimen dan yang baru. Kami melakukan ini karena kami melihat: perilaku pengguna lama berbeda dari perilaku pengguna baru. Karenanya, kita dapat, misalnya, tidak mengecat dalam grup dengan pengguna lama, tetapi mengecat dalam grup dengan pengguna baru, atau sebaliknya. Jika kita melakukan percobaan pada seluruh massa, kita mungkin tidak melihat ini.



Mari kita lihat eksperimen ini. Kami melihat konfigurasi percobaan berikut - Penerjemah untuk App Store, pengguna baru. Blokir studi, penerjemah nama, kelompok enabled_new. Awalan baru berarti kami mendeskripsikan konfigurasi untuk banyak pengguna yang baru. Berat 500 (jika jumlah semua bobot adalah 1000, maka kekuatan set ini adalah 50%). Kontrol_new, berat 500, ini adalah kelompok kedua. Dan hal yang paling menarik adalah filter untuk saluran STABLE, yaitu untuk rakitan yang dirakit untuk produksi. Versi di mana fitur muncul: 19.4.1. Dan di sini adalah tag min_install_date. Di sini, dalam format waktu Unix, itu dienkripsi pada 18 April 2019. Ini adalah beberapa hari setelah rilis versi 19.4.1.

Ada satu bagian lagi di sini selain awalan baru, itu diaktifkan dan kontrol. Ini adalah awalan kontrol, ini bukan kebetulan. Dan di samping fakta bahwa kami memecah pengguna menjadi baru dan lama, kami memecah mereka menjadi kelompok dalam percobaan menjadi beberapa bagian.



Bagian pertama pengguna adalah grup kontrol, yang memiliki awalan kontrol. Tidak ada fitur di dalamnya. Dia memiliki bobot X. Dia juga memiliki grup fitur, biasanya disebut diaktifkan. Ini juga memiliki bobot X, dan ini penting: ada fitur yang harus dihidupkan. Dan ada grup default yang memiliki bobot 1 minus 2X (1000 minus 2X, karena 1000 adalah nilai bobot total semua grup dalam konfigurasi yang sama, yang diterima secara default). Grup default juga tidak menyertakan fitur apa pun. Ini hanya menyimpan pengguna yang tetap setelah dipecah menjadi kontrol dan fitur. Anda juga dapat menjalankan kembali percobaan dari itu, jika perlu.



Mari kita lihat, katakanlah, konfigurasi untuk pengguna lama. Kami akan melihat fitur dan grup kontrol di sini. enabled_old - unggulan. control_old, - control, 10%. default_old - default, 80%.

Filter catatan, ya_min_version 19.4.1, max_install_date 28 Maret 2019. Ini adalah tanggal yang lebih awal dari tanggal rilis. Dengan demikian, ini adalah konfigurasi dengan daftar pengguna yang menerima versi 19.4.1 setelah pembaruan. Mereka menggunakan aplikasi dan sekarang menggunakan versi baru.

Mengapa kelompok fitur dan kontrol diperlukan? Dalam analitik yang saya perlihatkan pada slide pertama, kami membandingkan grup kontrol dan grup fitur. Mereka harus memiliki kekuatan yang sama sehingga metrik produk mereka dapat dibandingkan.

Dengan demikian, kami membandingkan grup kontrol dan fitur dalam analitik untuk grup pengguna yang berbeda, lama dan baru. Jika kita mengecat semuanya, maka kita menggulung fitur sebesar 100%.



Bagaimana cara kerja pengembang kode dengan sistem ini? Dia tahu nama-nama grup fitur, tanggal ketika fitur perlu diaktifkan, dan menulis beberapa lapisan akses, ini adalah pseudocode, meminta grup aktif dengan nama eksperimen. Mungkin tidak. Sebenarnya, semua konfigurasi mungkin tidak sesuai dengan kondisi perangkat. Maka string kosong akan kembali.

Setelah itu, jika nama grup yang aktif ditampilkan, maka Anda harus mengaktifkan fitur tersebut, jika tidak matikan. Lebih lanjut, fungsi ini sudah digunakan dalam kode, yang mencakup fungsionalitas dalam kode browser.



Jadi kami hidup dengan sistem eksperimen ini selama beberapa tahun. Semuanya baik-baik saja, tetapi mengungkapkan sejumlah kekurangan. Kelemahan pertama dari pendekatan ini adalah tidak mungkin untuk menambah grup eksperimen baru tanpa memperbaiki kode. Artinya, jika nama percobaan tidak mungkin berubah untuk fitur, kemudian menambahkan beberapa grup tambahan, itu bisa dengan mudah. Tetapi kode aksesibilitas fitur Anda tidak tahu grup seperti itu, karena Anda tidak memperkirakannya sebelumnya. Karenanya, Anda perlu memutar versi, bereksperimen dengan versi ini, yang merupakan masalah. Artinya, perlu, dengan mengubah kode, untuk membangun kembali dan memposting di App Store.

Kedua, Anda tidak dapat meluncurkan bagian fitur atau memecah fitur menjadi bagian setelah Anda memulai percobaan. Yaitu, jika Anda tiba-tiba memutuskan bahwa beberapa fitur dapat diluncurkan, dan beberapa masih tersisa dalam percobaan, maka Anda tidak dapat melakukan ini, Anda harus berpikir terlebih dahulu dan memecah fitur ini menjadi dua, dan menerimanya secara independen dalam percobaan.

Ketiga, Anda tidak dapat mengonfigurasi fitur atau membandingkan konfigurasi. Di Translator, misalnya, ada parameter - timeout time ke Translator API. Artinya, jika kami tidak berhasil menerjemahkan dalam beberapa milidetik, maka kami mengatakan bahwa, coba lagi, kesalahan, tidak berhasil.

Tidak mungkin untuk menetapkan batas waktu ini dalam percobaan, karena kami harus memperbaiki grup dan segera terlebih dahulu, mari kita buat grup berikut sebelumnya - enabled_with_300_ms, enabled_with_600_ms yang namanya nilai parameter dikodekan. Tetapi tidak mungkin untuk mengatur parameter secara numerik. Jika kita belum memikirkan hal ini sebelumnya, maka kita tidak dapat lagi membandingkan beberapa konfigurasi.

Keempat, analis dan pengembang dipaksa untuk menyetujui nama grup terlebih dahulu. Artinya, agar pengembang dapat mulai mengembangkan fitur, ia biasanya memulai, pada kenyataannya, dengan kebijakan ketersediaan fitur ini. Dan dia perlu tahu nama-nama grup fitur. Dan untuk ini, analis harus menjelaskan mekanisme percobaan - apakah kita akan membagi pengguna menjadi yang baru dan yang lama atau semua pengguna akan berada dalam kelompok yang sama tanpa pembagian.

Atau bisa juga eksperimen terbalik. Misalnya, kami dapat segera mempertimbangkan bahwa fitur ini diaktifkan, tetapi dapat mematikannya. Ini tidak terlalu menarik bagi analis, karena fitur ini belum siap. Dia akan menentukan mekanisme percobaan ketika siap. Dan pengembang membutuhkan nama-nama kelompok dan mekanisme percobaan di muka, jika tidak, ia harus terus-menerus membuat perubahan pada kode.

Kami berkonsultasi dan memutuskan bahwa itu cukup untuk bertahan. Maka proyek Make Experiments Great Again lahir.



Gagasan utama dari proyek ini adalah sebagai berikut. Jika sebelumnya kita dilampirkan ke kode, kode ke nama-nama grup aktif yang diteruskan analis kepada kita, sekarang kita telah menambahkan dua entitas tambahan. Fitur ini (Fitur) dan parameter fitur (FeatureParam). Dan dengan demikian, programmer menciptakan fitur dan parameter fitur secara mandiri, memilih pengidentifikasi untuk mereka, memilih nilai default untuk mereka, dan memprogram ketersediaan fitur untuk mereka.

Setelah itu, ia meneruskan pengidentifikasi ini kepada analis, dan analis tersebut, yang memikirkan mekanisme percobaan, menentukannya secara khusus dalam grup eksperimen menggunakan tag feature_association. Jika grup ini menjadi aktif, maka harap diingat untuk mengaktifkan atau menonaktifkan fitur dengan pengidentifikasi ini dan itu, dan mengatur parameter dengan pengidentifikasi tersebut.



Seperti apa bentuknya dalam file konfigurasi eksperimen? Di sini kita melihat kelompok eksperimen. Nama diaktifkan, tag feature_association opsional ditambahkan, dalam tag perintah enable_feature atau disable_feature ini, dan pengidentifikasi ditambahkan.

Ada juga blok param, yang bisa ada beberapa. Di sini, juga, ada nama - batas waktu, dan nilai yang perlu diatur ditambahkan.



Seperti apakah ini dari kode? Programmer menyatakan entitas dari kelas Fitur dan FeatureParam. Dan itu menulis nilai dari primitif ini ke lapisan akses fitur. Kemudian ia meneruskan pengidentifikasi ini ke analis, dan itu sudah dalam file konfigurasi menetapkan pengidentifikasi di blok grup eksperimen menggunakan tag feature_association. Segera setelah grup eksperimen menjadi aktif, nilai fitur dan parameter dengan pengidentifikasi ini dalam kode ditetapkan dari file. Jika tidak ada parameter dan fitur dalam grup, nilai-nilai default digunakan, yang ditunjukkan dari kode.

Tampaknya ini memberi kita? Pertama, ketika menambahkan grup baru, analis tidak perlu meminta programmer untuk menambahkan grup fitur baru ke kode, karena lapisan akses data beroperasi dengan pengidentifikasi yang tidak berubah ketika grup baru ditambahkan ke sistem percobaan.

Kedua, kami memposting waktu ketika programmer datang dengan pengidentifikasi ini untuk fitur dan parameter fitur, dengan waktu ketika analis mengembangkan mekanisme percobaan. Analis berkembang ketika fitur siap, dan programmer datang dengan pengidentifikasi ini ketika ia menulis kode, di awal.

Ini juga memungkinkan Anda untuk memecah fitur menjadi beberapa bagian. Misalkan ada fitur yang disebut Penerjemah, yang mencakup, pada kenyataannya, Penerjemah. Dan ada fitur TranslateServiceAPITimeout, itu termasuk fungsionalitas tambahan yang dapat mengatur batas waktu khusus untuk API Penerjemah. Dengan demikian, kita dapat melakukan dua kelompok percobaan, yang keduanya mengaktifkan Penerjemah, tetapi pada saat yang sama kita membandingkan nilai mana yang lebih baik: 300 milidetik atau 600.

. . (FeatureParam).

, , , . , , . , , . . ?



, : Feature FeatureParam. Feature FeatureParam . , Feature FeatureParam, , . . - , , .

-, Feature&FeatureParam. , «», , , . FeatureParam , , API β€” 300 600 ?

. . - , . public beta, . , .

, : .



? , , .

: . URL, , .

: browser://version β€” show-variations-cmd. : cheat-, . : .



. , . proto- - , study-, . , . Feature&FeatureParam, . , , . , , Feature&FeatureParam .

. proto- . . , . , , .



Yang kedua. Feature&FeatureParam? Chromium, . Chromium browser://version, show-variations-cmd.

: enabled-features, force-fieldtrials force-fieldtrials-params, . , . ? , . , Feature1 trial1. Feature2 trial2. Feature3 .

trial1 group1. trial2 group2. force-fieldtrials-params, , trial1 group1, p1 v1, p2 v2. trial2 group2, p3 v3, p4 v4.

, . Chromium, iOS. , .

. --force-fieldtrials=translator/enabled_new/ enabled_new translator.

--force-fieldtrial-params==translator.enablew_new:timeout/5000, translator enabled_new, , , translator, enabled_new timeout, 5 000 .

--enabled-features=TranslateServiceAPITimeout<translator , - translator translator , , , TranslateServiceAPITimeout. , , , , .



(cheat urls). , , , , , , . . . .

yandexbrowser:// (.), , . . my_pet_experiment=group_name. , enable-features=, , disable-features=, . , &.

(cheat url), . , , , . , , . filter, my_pet_experiment , . 1000, feature_association, , .

, . , , . , β€” my_pet_experiment β€” , , . , , study .



, . β€” , . . , .

, .



, , , , . , . , .

. . , , ? , . , ?

. .



, . , , UUID, application Identifier, . . hash .

? ? , , UUID, . ? , , . . ? hash hash , . , Google, An Efficient Low-Entropy Provider.

, β€” UUID, , , . , , Chromium.

, , ? ? :

  1. : , -. .
  2. . , , , .
  3. Bisa diuji Anda harus memiliki mekanisme yang memungkinkan Anda untuk mendefinisikan kembali nilai-nilai grup, fitur, parameter, atau entitas lain yang Anda butuhkan.
  4. Di mana primitif berbeda digunakan untuk analitik dan pemrograman.
  5. Dapat diperluas. Anda harus memiliki kesempatan untuk melihat cara kerjanya dan menyesuaikannya dengan kebutuhan Anda (lihat layanan variasi Chromium ).

Sistem Chromium, yang kami kembangkan di Yandex.Browser untuk iOS, memiliki kriteria seperti itu. Lakukan eksperimen, analisis, dan buat aplikasi lebih baik. Terima kasih

Source: https://habr.com/ru/post/id475012/


All Articles