साइट के रूट लेआउट में एक साझा फ़ंक्शन ने A/B-टेस्ट एक्सपोज़र काउंटर को पेज-व्यू काउंटर में बदल दिया, जिससे सैंपल साइज बढ़ गया और कन्वर्जन रेट अर्थहीन हो गए। होमपेज के 50/50 स्प्लिट वाले इस टेस्ट में, एक वेरिएंट के लिए 178 हिट्स और दूसरे के लिए 57 हिट्स दर्ज किए गए—जो अपेक्षित समान विभाजन से बहुत दूर थे।
यह त्रुटि रैंडमाइज़र (randomizer) से कैसे बच निकली
डेवलपर ने सबसे पहले उस रैंडमाइज़र की जांच की जो विज़िटर्स को वेरिएंट असाइन करता है। उसने मिडलवेयर (middleware) को पढ़ा, कुकी लॉजिक का निरीक्षण किया और एक स्क्रिप्ट चलाई जिसने असाइनमेंट फ़ंक्शन को 10,000 बार कॉल किया; इसने एक सटीक 50/50 स्प्लिट दिया। रैंडमाइज़र खुद सही काम कर रहा था; समस्या यह थी कि एक्सपोज़र को कैसे रिकॉर्ड किया जा रहा था।
एक ही फ़ंक्शन दो काम कर रहा था:
- वेरिएंट सेट करना – विज़िटर के अनुभव को सुसंगत बनाए रखने के लिए हर पेज लोड पर चलता है।
- एक्सपोज़र इवेंट रिकॉर्ड करना – यह प्रति विज़िटर केवल एक बार चलना चाहिए, ठीक उसी क्षण जब वेरिएंट पहली बार दिखाई दे।
यह फ़ंक्शन रूट लेआउट में था, जो हर नेविगेशन पर रेंडर होने वाला एक कंपोनेंट है। चूंकि एक्सपोज़र-रिकॉर्डिंग कोड हर बार लेआउट रेंडर होने पर चलता था, इसलिए हर पेज व्यू को एक नया एक्सपोज़र माना गया। होमपेज के दोनों वेरिएंट्स अलग-अलग लेआउट ट्री का उपयोग कर रहे थे, इसलिए उनके पेज-व्यू रेट अलग-अलग हो गए, जिससे ऐसा भ्रम पैदा हुआ कि रैंडमाइज़र खराब है।
गलत गिनती क्यों मायने रखती थी
कन्वर्जन नंबर—क्लिक-थ्रू, साइन-अप, खरीदारी—सही ढंग से लॉग किए गए थे। लेकिन हर (denominator) (एक्सपोज़र की संख्या) गलत थी। गणना किए गए कन्वर्जन रेट वास्तविकता से बहुत कम दिखाई दे रहे थे, और उन रेट्स के आधार पर लिए गए कोई भी निर्णय अविश्वसनीय थे।
विसंगति सामने आने से पहले टेस्ट दो सप्ताह तक चला, जिससे टीम को पूरा डेटा सेट छोड़ना पड़ा।
समाधान
समाधान सीधा था: जिम्मेदारियों को अलग-अलग फ़ंक्शंस में बाँट दिया गया। एक्सपोज़र-रिकॉर्डिंग कोड अब यह जांचता है कि विज़िटर को पहले ही गिना जा चुका है या नहीं, और प्रति उपयोगकर्ता केवल एक बार चलता है। वेरिएंट-सेटिंग कोड वहीं रहता है, जो हर नेविगेशन पर चलता रहता है।
प्रयोग चलाने वाले किसी भी व्यक्ति के लिए तीन मुख्य बातें
- स्टेट-सेटिंग (state-setting) को वन-ऑफ इवेंट्स (one-off events) से अलग रखें। एक ऐसा फ़ंक्शन जो वेरिएंट असाइन भी करता है और एक्सपोज़र भी लॉग करता है, आपस में टकराएगा क्योंकि पहला बार-बार चलता है जबकि दूसरे को नहीं चलना चाहिए।
- रूट लेआउट में वन-शॉट लॉजिक (one-shot logic) से बचें। किसी ऐसे कंपोनेंट में रखी गई कोई भी चीज़ जो हर पेज लोड पर रेंडर होता है, वह बार-बार चलेगी, जिससे "प्रति विज़िटर एक बार" बदलकर "प्रति पेज व्यू एक बार" हो जाएगा।
- जब देखा गया स्प्लिट रैंडमाइज़र के विपरीत हो, तो सबसे पहले काउंटर का ऑडिट करें। डेवलपर्स अक्सर रैंडमाइज़र की निष्पक्षता का परीक्षण करते हैं लेकिन शायद ही कभी यह सत्यापित करते हैं कि गिनती करने का तंत्र (counting mechanism) सटीक है।
आगे क्या ध्यान रखें
एक्सपोज़र के लिए किसी भी ऐसे प्रयोग पर ऑडिट किया जाना चाहिए जो एक सिंगल काउंटर पर निर्भर करता है कि वह काउंटर कंपोनेंट ट्री में कहाँ स्थित है। यदि काउंटर एक ग्लोबल लेआउट में है, तो एक ऐसा चेक जोड़ें जो इवेंट को एक स्थायी पहचानकर्ता (persistent identifier)—जैसे कि कुकी या लोकल-स्टोरेज फ्लैग—से जोड़ता हो। टीमों को अपने डैशबोर्ड में एक सैनिटी चेक (sanity check) भी बनाना चाहिए: यदि देखा गया वेरिएंट वितरण एक छोटे सांख्यिकीय मार्जिन से अधिक विचलित होता है, तो रैंडमाइज़र के खराब होने का अनुमान लगाने से पहले काउंटर ऑडिट के लिए टेस्ट को फ्लैग करें।
संक्षेप में, एक भरोसेमंद एक्सपोज़र काउंट के बिना अच्छी तरह से काम करने वाला रैंडमाइज़र बेकार है। जिम्मेदारियों को विभाजित करना और वन-ऑफ इवेंट्स को हमेशा रेंडर होने वाले कंपोनेंट्स से बाहर रखना A/B टेस्ट को सटीक बनाए रखता है और हफ्तों की बर्बाद विश्लेषण से बचाता है।
