Django आधारित परियोजना में ए/बी परीक्षण पर कोई विचार?




testing ab-testing (6)

Django-दुबला भयानक लग रहा है। मैं इसे अभी भी समझने की कोशिश करने जा रहा हूं। मैंने अपना खुद का समाधान शुरू कर दिया जो मैं करने की कोशिश कर रहा था उसके लिए पर्याप्त है। मैंने इसे अच्छी तरह से पैकेज करने की कोशिश की है और शुरुआत के लिए इसका उपयोग करना आसान बना दिया है। यह बहुत बुनियादी है, इसे आज़माएं:

https://github.com/crobertsbmw/RobertsAB

हमने अभी हमारे डीजेगो आधारित परियोजना के लिए ए / बी परीक्षण करना शुरू कर दिया है। क्या मुझे इस ए / बी परीक्षण के बारे में सर्वोत्तम प्रथाओं या उपयोगी अंतर्दृष्टि पर कुछ जानकारी मिल सकती है।

आदर्श रूप से प्रत्येक नए परीक्षण पृष्ठ को एक पैरामीटर (जैसे जीमेल की तरह) से अलग किया जाएगा। mysite.com/?ui=2 को एक अलग पृष्ठ देना चाहिए। इसलिए प्रत्येक दृश्य के लिए मुझे 'ui' पैरामीटर मान के आधार पर विभिन्न टेम्पलेट्स लोड करने के लिए एक सजावट लिखने की आवश्यकता है। और मैं सजावटी में किसी भी टेम्पलेट नाम को हार्ड कोड नहीं करना चाहता हूं। तो urls.py url पैटर्न कैसे होगा?


कोड में डाइविंग से पहले ए / बी परीक्षण करने की कोशिश कर रहा है, यह एक कदम पीछे और अमूर्त लेने के लिए उपयोगी है। परीक्षण करने के लिए हमें वास्तव में क्या करना होगा?

  • एक लक्ष्य जिसमें एक शर्त है
  • लक्ष्य की स्थिति को पूरा करने के लिए कम से कम दो अलग-अलग पथ
  • पथों में से एक को दर्शकों को भेजने के लिए एक प्रणाली
  • परीक्षण के परिणामों को रिकॉर्ड करने के लिए एक प्रणाली

इस बात को ध्यान में रखते हुए चलो कार्यान्वयन के बारे में सोचें।

लक्ष्य

जब हम वेब पर किसी लक्ष्य के बारे में सोचते हैं तो आम तौर पर हमारा मतलब है कि कोई उपयोगकर्ता किसी निश्चित पृष्ठ तक पहुंचता है या वे एक विशिष्ट कार्यवाही पूरी करते हैं, उदाहरण के लिए सफलतापूर्वक उपयोगकर्ता के रूप में पंजीकरण करना या चेकआउट पृष्ठ पर जाना।

Django में हम मॉडल को दो तरीकों से मॉडल कर सकते हैं - संभवतः एक दृश्य के अंदर मूर्खतापूर्ण, जब भी कोई लक्ष्य पहुंचा जाता है तो फ़ंक्शन को कॉल करना:

    def checkout(request):
        a_b_goal_complete(request)
        ...

लेकिन इससे मदद नहीं मिलती है क्योंकि हमें हर जगह उस कोड को जोड़ना होगा, हमें इसकी आवश्यकता है - इसके अलावा यदि हम किसी भी प्लग करने योग्य ऐप्स का उपयोग कर रहे हैं तो हम अपने ए / बी परीक्षण को जोड़ने के लिए अपने कोड को संपादित नहीं करना चाहते हैं।

हम सीधे कोड कोड संपादित किए बिना ए / बी लक्ष्य कैसे पेश कर सकते हैं? मिडलवेयर के बारे में क्या?

    class ABMiddleware:
      def process_request(self, request):
          if a_b_goal_conditions_met(request):
            a_b_goal_complete(request)

इससे हमें साइट पर कहीं भी ए / बी लक्ष्यों को ट्रैक करने की अनुमति मिल जाएगी।

हम कैसे जानते हैं कि लक्ष्य की शर्तों को पूरा किया गया है? कार्यान्वयन की आसानी के लिए मैं सुझाव दूंगा कि हम जानते हैं कि एक लक्ष्य को उपयोगकर्ता की विशिष्ट URL पथ तक पहुंचने पर इसकी शर्तों को पूरा किया गया था। एक बोनस के रूप में हम इसे एक हाथ के अंदर गंदे हाथों के बिना माप सकते हैं। उपयोगकर्ता को पंजीकृत करने के हमारे उदाहरण पर वापस जाने के लिए हम कह सकते हैं कि जब उपयोगकर्ता यूआरएल पथ तक पहुंचता है तो यह लक्ष्य पूरा हो गया है:

/पंजीकरण पूर्ण

तो हम a_b_goal_conditions_met को परिभाषित a_b_goal_conditions_met :

     a_b_goal_conditions_met(request):
       return request.path == "/registration/complete":

पथ

Django में पथों के बारे में सोचते समय विभिन्न टेम्पलेट्स का उपयोग करने के विचार पर कूदना स्वाभाविक है। क्या एक और तरीका खोजा जाना बाकी है। ए / बी परीक्षण में आप दो पृष्ठों के बीच छोटे अंतर बनाते हैं और परिणामों को मापते हैं। इसलिए यह एक एकल आधार पथ टेम्पलेट को परिभाषित करने का सबसे अच्छा अभ्यास होना चाहिए जिससे लक्ष्य के सभी पथों का विस्तार किया जाना चाहिए।

इन टेम्पलेट्स को कैसे प्रस्तुत करना चाहिए? एक सजावटी शायद एक अच्छी शुरुआत है - यह Django में आपके विचारों में पैरामीटर template_name शामिल करने का सबसे अच्छा अभ्यास है, एक सजावटी रनटाइम पर इस पैरामीटर को बदल सकता है।

    @a_b
    def registration(request, extra_context=None, template_name="reg/reg.html"):
       ...

आप इस सजावटी को या तो लपेटा हुआ फ़ंक्शन आत्मनिरीक्षण कर सकते हैं और template_name तर्क को संशोधित कर सकते हैं या कहीं से (जैसे मॉडल) से सही टेम्पलेट देख सकते हैं। अगर हम हर समारोह में सजावटी नहीं जोड़ना चाहते थे तो हम इसे हमारे एबीएमडलवेयर के हिस्से के रूप में कार्यान्वित कर सकते हैं:

    class ABMiddleware:
       ...
       def process_view(self, request, view_func, view_args, view_kwargs):
         if should_do_a_b_test(...) and "template_name" in view_kwargs:
           # Modify the template name to one of our Path templates
           view_kwargs["template_name"] = get_a_b_path_for_view(view_func)
           response = view_func(view_args, view_kwargs)
           return response

ए / बी परीक्षण चलने वाले विचारों के ट्रैक रखने के लिए हमें कुछ रास्ता जोड़ने की भी आवश्यकता होगी।

दर्शकों को पथ के नीचे भेजने के लिए एक प्रणाली

सिद्धांत रूप में यह आसान है लेकिन कई अलग-अलग कार्यान्वयन हैं इसलिए यह स्पष्ट नहीं है कि कौन सा सबसे अच्छा है। हम जानते हैं कि एक अच्छी प्रणाली को उपयोगकर्ताओं को पथ के समान समान रूप से विभाजित करना चाहिए - कुछ हैश विधि का उपयोग किया जाना चाहिए - शायद आप पथों की संख्या से विभाजित मेमकेचे काउंटर के मॉड्यूलस का उपयोग कर सकते हैं - शायद एक बेहतर तरीका है।

टेस्ट के परिणामों को रिकॉर्ड करने के लिए एक प्रणाली

हमें यह रिकॉर्ड करने की ज़रूरत है कि कितने उपयोगकर्ता नीचे गए पथ - उपयोगकर्ता द्वारा लक्ष्य तक पहुंचने पर हमें इस जानकारी तक पहुंच की भी आवश्यकता होगी (हमें यह कहने में सक्षम होना चाहिए कि वे लक्ष्य की स्थिति को पूरा करने के लिए किस मार्ग से नीचे आए थे) - हम जब तक उपयोगकर्ता लक्ष्य की स्थिति को पूरा नहीं करता तब तक पथ जानकारी को जारी रखने के लिए डेटा और या तो Django सत्र या कुकीज़ रिकॉर्ड करने के लिए किसी प्रकार का मॉडल (ओं) का उपयोग करेगा।

समापन विचार

मैंने Django में ए / बी परीक्षण को कार्यान्वित करने के लिए बहुत सारे छद्म कोड दिए हैं - उपरोक्त किसी भी पूर्ण समाधान से नहीं बल्कि Django में ए / बी परीक्षण के लिए पुन: प्रयोज्य रूपरेखा बनाने की दिशा में अच्छी शुरुआत है।

संदर्भ के लिए आप गिटहब पर पॉल मार के सात मिनट ए / बी को देखना चाह सकते हैं - यह उपर्युक्त का आरओआर संस्करण है! http://github.com/paulmars/seven_minute_abs/tree/master

अद्यतन करें

Google वेबसाइट ऑप्टिमाइज़र के आगे प्रतिबिंब और जांच पर यह स्पष्ट है कि उपर्युक्त तर्क में अंतर छेद हैं। पथों का प्रतिनिधित्व करने के लिए विभिन्न टेम्पलेट्स का उपयोग करके आप दृश्य पर सभी कैशिंग को तोड़ते हैं (या यदि दृश्य कैश किया जाता है तो यह हमेशा एक ही पथ की सेवा करेगा!)। इसके बजाय, पथों का उपयोग करने के बजाय, मैं इसके बजाय जीडब्ल्यूओ शब्दावली चुरा लेगा और Combinations के विचार का उपयोग करूंगा - यह एक टेम्पलेट बदलने का एक विशिष्ट हिस्सा है - उदाहरण के लिए, किसी साइट के <h1> टैग को बदलना।

समाधान में टेम्पलेट टैग शामिल होंगे जो जावास्क्रिप्ट को प्रस्तुत करेंगे। जब ब्राउज़र ब्राउज़र में लोड होता है तो जावास्क्रिप्ट आपके सर्वर से अनुरोध करता है जो संभावित संयोजनों में से एक प्राप्त करता है।

कैशिंग को संरक्षित करते समय आप प्रति पेज एकाधिक संयोजनों का परीक्षण कर सकते हैं!

अद्यतन करें

अभी भी टेम्पलेट स्विचिंग के लिए कमरा है - उदाहरण के लिए कहें कि आप एक बिल्कुल नया होमपेज पेश करते हैं और पुराने होमपेज के खिलाफ अपने प्रदर्शन का परीक्षण करना चाहते हैं - आप अभी भी टेम्पलेट स्विचिंग तकनीक का उपयोग करना चाहते हैं। ध्यान रखने योग्य बात यह है कि आपको पेज के कैश किए गए संस्करणों के एक्स संख्या के बीच स्विच करने के लिए कुछ तरीका पता लगाना होगा। ऐसा करने के लिए आपको यह देखने के लिए मानक कैश किए गए मिडलवेयर को ओवरराइड करना होगा कि क्या अनुरोधित यूआरएल पर उनका ए / बी परीक्षण चल रहा है या नहीं। फिर यह दिखाने के लिए सही कैश संस्करण का चयन कर सकते हैं !!!

अद्यतन करें

ऊपर वर्णित विचारों का उपयोग करके मैंने मूल ए / बी परीक्षण Django के लिए एक प्लग करने योग्य ऐप लागू किया है। आप इसे गितूब से निकाल सकते हैं:

http://github.com/johnboxall/django-ab/tree/master


जस्टिन वास द्वारा एक के आधार पर एक कोड:

def ab_test(force = None):
    def _ab_test(view):
        def wrapped_view(request, *args, **kwargs):
            request, template_name, cont = view(request, *args, **kwargs)
            if 'ui' in request.GET:
                request.session['ui'] = request.GET['ui']
            if 'ui' in request.session:
                cont['ui'] = request.session['ui']
            else:
                if force is None:
                    cont['ui'] = '0'
                else:
                    return redirect_to(request, force)
            return direct_to_template(request, template_name, extra_context = cont)
        return wrapped_view
    return _ab_test

कोड का उपयोग कर उदाहरण समारोह:

@ab_test()
def index1(request):
    return (request,'website/index.html', locals())

@ab_test('?ui=33')
def index2(request):
    return (request,'website/index.html', locals())

यहां क्या होता है: 1. उत्तीर्ण यूआई पैरामीटर सत्र चर 2 में संग्रहीत होता है। एक ही टेम्पलेट हर बार लोड होता है, लेकिन एक संदर्भ चर {{ui}} यूआई आईडी स्टोर करता है (आप टेम्पलेट को संशोधित करने के लिए इसका उपयोग कर सकते हैं) 3। यदि उपयोगकर्ता बिना पेज के प्रवेश करता है? Ui = xx तो index2 के मामले में उसे '? Ui = 33' पर रीडायरेक्ट किया गया है, index1 के मामले में यूआई वैरिएबल 0 पर सेट है।

मैं मुख्य पृष्ठ से Google वेबसाइट ऑप्टिमाइज़र पर रीडायरेक्ट करने के लिए 3 का उपयोग करता हूं जो बदले में उचित पृष्ठ के साथ मुख्य पृष्ठ पर रीडायरेक्ट करता है? Ui पैरामीटर।



यदि आप जीईटी पैरामीटर का उपयोग करते हैं जैसे आपने सुझाया है ( ?ui=2 Ui ?ui=2 ), तो आपको urls.py को बिल्कुल स्पर्श नहीं करना चाहिए। आपका सजावटी request.GET['ui'] का निरीक्षण कर सकता है। request.GET['ui'] और उसे क्या चाहिए इसकी तलाश करें।

हार्डकोडिंग टेम्पलेट नामों से बचने के लिए, शायद आप व्यू फ़ंक्शन से रिटर्न वैल्यू को लपेट सकते हैं? Render_to_response के आउटपुट को वापस करने के बजाय, आप (template_name, context) का एक टुपल वापस कर सकते हैं और सजावटी को टेम्पलेट नाम को उलझाने दें। इस जैसे किसी और के बारे में क्या राय है? चेतावनी: मैंने इस कोड का परीक्षण नहीं किया है

def ab_test(view):
    def wrapped_view(request, *args, **kwargs):
        template_name, context = view(request, *args, **kwargs)
        if 'ui' in request.GET:
             template_name = '%s_%s' % (template_name, request.GET['ui'])
             # ie, 'folder/template.html' becomes 'folder/template.html_2'
        return render_to_response(template_name, context)
    return wrapped_view

यह वास्तव में एक मूल उदाहरण है, लेकिन मुझे उम्मीद है कि यह विचार पूरे हो जाएगा। आप प्रतिक्रिया के बारे में कई अन्य चीजों को संशोधित कर सकते हैं, जैसे टेम्पलेट संदर्भ में जानकारी जोड़ना। उदाहरण के लिए, आप Google Analytics जैसे आपकी साइट एनालिटिक्स के साथ एकीकृत करने के लिए उन संदर्भ चर का उपयोग कर सकते हैं।

बोनस के रूप में, यदि आप जीईटी पैरामीटर का उपयोग करना बंद कर देते हैं और कुकीज आदि के आधार पर कुछ ले जाते हैं तो आप भविष्य में इस सजावट को दोबारा कर सकते हैं।

अपडेट करें यदि आपके पास पहले से ही बहुत सारे विचार लिखे गए हैं, और आप उन्हें सभी संशोधित नहीं करना चाहते हैं, तो आप render_to_response का अपना संस्करण लिख सकते हैं।

def render_to_response(template_list, dictionary, context_instance, mimetype):
    return (template_list, dictionary, context_instance, mimetype)

def ab_test(view):
    from django.shortcuts import render_to_response as old_render_to_response
    def wrapped_view(request, *args, **kwargs):
        template_name, context, context_instance, mimetype = view(request, *args, **kwargs)
        if 'ui' in request.GET:
             template_name = '%s_%s' % (template_name, request.GET['ui'])
             # ie, 'folder/template.html' becomes 'folder/template.html_2'
        return old_render_to_response(template_name, context, context_instance=context_instance, mimetype=mimetype)
    return wrapped_view

@ab_test
def my_legacy_view(request, param):
     return render_to_response('mytemplate.html', {'param': param})

ये जवाब बेवकूफ लगते हैं। आजकल, Google Analytics शायद अधिकांश साइटों के लिए सबसे लोकप्रिय और सर्वोत्तम निःशुल्क विकल्प है। Google Analytics के साथ django को एकीकृत करने के लिए यहां कुछ संसाधन दिए गए हैं:

प्लगइन्स :

कैसे टॉस :







ab-testing