A/B Testing using Django

Share on facebook
Share on twitter
Share on linkedin
A/B Testing Using Django

When I make any change on my web page, I always wonder if this change affects the user experience. Here I will be sharing my thoughts on A/B Testing using Django, which I often use in these scenarios before finalizing any change. However, Online training on Python can help you understand the concepts mentioned below.

What is Django?

Django is a framework used for web development. It is written in Python. It is a free and open-source tool. It is a complete tool for a web developer. It can work with any framework used on the client-side. It provides an output in almost all possible formats like HTML, JSON, XML, etc.

It is a secured framework. It can store the session information in the database instead of keeping it in the cookie. It saves the password hash instead of directly holding the password. We can easily add hardware at any level of the architecture to manage higher traffic to the website.

The code written in Django is reusable and easy to maintain. As the code is written in Python, it can be used on several platforms like Windows, Linux, Mac, etc.

What is A/B Testing?

Bucket testing or split testing are alternative names for A/B Testing. It is a method by which the developer verifies different versions of the web page or software application. During these experiments, other users will be using different versions of the web page and based on their response, corrective actions, if needed, are taken.

During this analysis, direct questions related to change are asked for which data is collected. This data set is considered to study the impact.

Why is A/B Testing used?

When a user visits or page for different reasons, they are lost a couple of times trying to find the right button to click or find the demo button, and so on. This results in loss of interest for the visitor, and conversion doesn’t happen. As a result, this or ROI is impacted. So with A/B testing, we can improve our ROI with a better customer experience. Due to the exception mismatch, or many other reasons, the bounce rate may be high for our website. This can be reduced using A/B testing, and our customers can spend more time on our website.

A/B Testing will also prevent you from making significant modifications that can impact the ROI. In such a case, you can make smaller improvements to test its usability, and if it works fine, go ahead with other small modifications. The entire change is done in steps saving any trouble that could have been caused due to the significant modification done at once. It is a statistical method used to judge who the winner is and who the loser is. This is full-proof testing of your website to give you better performance and user experience. 

Working principle of A/B testing?

The users trying to access the page is divided into two user groups. In this testing, one set of users will be directed to the original web page. While the other set of users are referred to the updated version of the web page.

The next step is to analyze the activities done by the different sets of users on their respective pages. The critical data thus obtained is used to understand how useful the web page is for the user.

a/b testing for views

Steps that are taken for A/B testing using Django

  1. We divide our set of users into different buckets. We assign a bucket number starting from 1 to 150. Any random number can be chosen as per our needs. The higher the value, the more number of users test the performance of the page. This will give better results that can be used for further analysis. 
  2. We need to define two constants, the first being the view through which the user is routed. And the other being specifies the primary view.
  3. The tuple for the first constant will contain the range of the users of one bucket.
  4. The main view in the second constant will be used only when we do not want anonymous users been included for A/B testing.   

AB_TEST = {

        tuple(xrange(1,75)): demo_app.views.view_a’,

        tuple(xrange(75,150)): demo_app.views.view_b’,

    }

 

AB_TEST_PRIMARY = demo_app.views.view_a’

 

5. Two decorators are then written to wrap each view. The first decorator will handle the view while the other will take the template.

6. The decorator would take the first constant that we defined as a dictionary view. It will also take the primary view, which is specified by the second constant. Along with this, it accepts a Boolean value that will determine if the anonymous users are included in A/B testing or not.

The function of decorator for any user that has logged in

v It will check what is the bucket number for the user

v It will also check which view is assigned to the user

After all these checks, it will return the corresponding view for the user.

However, in the case of an anonymous user who is not included in the testing, a primary view is returned.

In case if we want to include the anonymous user in the testing, we will need to,

v Assign a unique cookie to the user, which does not depend on the session.

v A fast and straightforward key-value pair is stored like Redis.

After making these settings then we need to take the below actions

v Get the unique cookie of the user.

v Validate if the key is present in Redis for the value of the cookie.

v If Redis returns a value, select the appropriate view.

v If Redis does not return a value, then choose a random view from the view dictionary.

v Now assign the corresponding user for the particular key along with the amount of the view.

v Now return the appropriate view satisfying the above conditions.

Using this strategy, the anonymous user will be included for A/B Testing, and the corresponding view will be allocated to it throughout the testing cycle.

Now let us consider code for a decorator that we can use for A/B Testing.

“””

Decorator to A/B test different views.

Args:

    primary_view:       Fallback view.

    anonymous_sticky:        Determines whether A/B testing should be performed on  

                        anonymous users as well.

    view_dict:          Dictionary for views that contains the buckets as keys.

“””

def ab_views(

        primary_view=None,

        anonymous _sticky=False,

        view_dict={}):

    def decorator(f):

        @wraps(f)

        def _ab_views(request, *args, **kwargs):

            # This is the block of code where  you may write anything that needs to be done        # on the view

            # ctx = f(request, *args, **kwargs)

            view = None

            try:

                if user_is_logged_in():

                    view = _get_view(request, f, view_dict, primary_view)

                else:

                    redis = initialize_redis_obj()

                    view = _get_view_anonymous(request, redis, f, view_dict,

                            primary_view, anonymous _sticky)

            except:

                view = primary_view

            view = str_to_func(view)

            return view(request, *args, **kwargs)

 

        def _get_view(request, f, view_dict, primary_view):

            bucket = get_user_bucket(request)

            view = get_view_for_bucket(bucket)

            return view

 

        def _get_view_anonymous(request, redis, f, view_dict,

                primary_view, anonymous _sticky):

            view = None

            if anonymous _sticky:

                cookie = get_cookie_from_request(request)

                if cookie:

                    view = get_value_from_redis(cookie)

                else:

                    view = random.choice(view_dict.values())

                    set_cookie_value_in_redis(cookie)

            else:

                view = primary_view

            return view

 

        return _ab_views

    return decorator

Now let us break the entire code and understand them.

7. If we have a regular user, it will first check whether the user is logged in or not. If logged in, it will return the view by checking in the view dictionary in the _get_view function().

        def _get_view(request, f, view_dict, primary_view):

            bucket = get_user_bucket(request)

            view = get_view_for_bucket(bucket)

            return view

8. If an anonymous user is logged in, it will check if the anonymous_sticky flag is true or false. If correct, it will check for the corresponding value for Redis’s view, depending on the cookie value that is returned. Otherwise, it will return a random view and set the cookie value in Redis.

If the anonymous_sticky flag is False, then it will return the primary view.

        def _get_view_anonymous(request, redis, f, view_dict,

                primary_view, anonymous _sticky):

            view = None

            if anonymous _sticky:

                cookie = get_cookie_from_request(request)

                if cookie:

                    view = get_value_from_redis(cookie)

                else:

                    view = random.choice(view_dict.values())

                    set_cookie_value_in_redis(cookie)

            else:

                view = primary_view

            return view

9. We also need to understand the code for the function str_to_fun(func_string). This function is used to return a view object based on the path of view.

 

def str_to_func (func_string):

    func = None

    func_string_splitted = func_string.split(‘.’)

    module_name = ‘.’.join(func_string_splitted[:-1])

    function_name = func_string_splitted[-1]

    module = import_module(module_name)

    if module and function_name:

        func = getattr(module, function_name)

    return func

 

This function will split the function using the “.” operator.and store it in the array function_string_splitted. It then segregates the module name and function name from it. It then gets the view object based on the function and module name and returns the view shown to the user.

We can do A/B testing on templates as well. This can be achieved by replacing the view dictionary with a template dictionary and returning a template.

Putting the views together

Let us call view A as view_a and view B as view_b, which are to be tested. Now let us write a new view view_ab. We will wrap this new view_ab with one of the decorators we used in the above code and create a unique URL pointing to this new view.

@ab_views(

        primary_view=AB_TEST_PRIMARY,

        anonymous_sticky=True,

        view_dict=AB_TEST,

        )

def view_ab(request):

    ctx = {}

    return ctx

Now from the above-written code, we can understand that the primary view is the new primary view AB_TEST_PRIMARY. Also, here, this piece of code is tested for anonymous users as well. Here, in this case, the modern view is returning to the dictionary.

Now the last thing we need to do is integrate the framework with analytics. This will help us in understanding which view performs better. You may use any tracking or analytics tool to evaluate the performance. However, we have used Mixedpanel to track the behavior of the users.

To do this experiment with A/B/C testing, the only change would be needed in the AB_TEST constant that has been used in the above code.

What should we take care of while doing A/B Testing?

  • If someone says this payment gateway works for them, you assume that it can work for you. If you don’t include that in your testing, it may give wrong results. So it would help if you had all possible cases after thorough research.
  • Even while undergoing the test rounds, you feel that it might give failed results. Don’t get discouraged. Continue with the test. The results might give you some other statistical insights which might be helpful in some different scenarios.
  • It would help if you took care that the duration of testing is significantly long that traffic to both users’ set is acceptable. Also, if the test is run for a short period or an extended period, it may give incorrect results. So the time factor should depend upon the existing traffic and conversion rate.
  • A failed test run should be used as a foundation for changes that need to be done for the next round of A/B testing.

To understand Django better, I would suggest you enroll in Python Training.3RI Technologies is a well-known institute that offers a holistically designed online course on Python. It is ISO 9001:2015 certified company providing training in different technology in IT.

They have a well-curated syllabus to cover all the concepts that are in demand in today’s industry. The trainers at their institutes have working experience of 8+ years as a Python expert in IT companies. Also, their focus is on hands-on training. The institute’s programs make all candidates job-ready, making it easier for them to get absorbed immediately after the course completion. 

They provide 100% placement assistance with their tie-ups with 300+ software companies across India. They have 1000+ students already placed through them and now working successfully in their new careers. They also provide help in preparing Resumes. They also conduct practice interview rounds. They also share the most commonly asked interview questions, which increase our chance of performing better in interviews in various companies. We can also attend their Personality development workshops to improve our soft skills as part of this Online Training on Python.

 At the end of the Python online training, you will also be awarded Python Online Course certification recognized by almost all industries.

 

Related blogs

Share

Share on facebook
Share on twitter
Share on linkedin
Share on tumblr
Share on whatsapp

        Learn the way industry wants it…

Call Now ButtonCall Now

Download

3RI Brochure

Enroll Now

Online Training Program

Enroll Now