Подтвердить что ты не робот

Любые мысли о тестировании A/B в проекте на основе Django?

Мы только что начали выполнять тестирование A/B для нашего проекта на основе Django. Могу ли я получить некоторую информацию о лучших практиках или полезной информации об этом тестировании A/B.

В идеале каждая новая страница тестирования будет отличаться одним параметром (как Gmail). mysite.com/?ui=2 должен дать другую страницу. Поэтому для каждого представления мне нужно написать декоратор для загрузки разных шаблонов на основе значения параметра "ui". И я не хочу жестко кодировать имена шаблонов в декораторах. Итак, как будет выглядеть URL-адрес urls.py?

4b9b3361

Ответ 1

Полезно сделать шаг назад и отвлечь то, что A/B тестирование пытается сделать, прежде чем погрузиться в код. Что именно нам нужно будет провести?

  • Цель, имеющая условие
  • Как минимум два разных пути для достижения цели цели
  • Система для отправки зрителей по одному из путей
  • Система записи результатов теста

С учетом этого подумайте о реализации.

Цель

Когда мы думаем о цели в Интернете, мы обычно подразумеваем, что пользователь достигает определенной страницы или выполняет определенное действие, например, успешно регистрируется как пользователь или попадает на страницу проверки.

В Django мы могли бы моделировать это несколькими способами - возможно, наивно внутри представления, вызывая функцию всякий раз, когда достигнут Цель:

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

Но это не помогает, потому что нам нужно будет добавить этот код везде, где он нам нужен - плюс, если мы будем использовать любые подключаемые приложения, мы бы предпочли не редактировать их код, чтобы добавить наш тест A/B.

Как мы можем ввести A/B Goals без прямого редактирования кода просмотра? Что относительно промежуточного ПО?

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

Это позволит нам отслеживать цели A/B в любом месте сайта.

Откуда мы знаем, что были достигнуты условия? Для простоты внедрения я предлагаю, чтобы мы знали, что цель достигнута, когда пользователь достиг определенного URL-адреса. В качестве бонуса мы можем измерить это, не загрязняя руки во взгляде. Чтобы вернуться к нашему примеру регистрации пользователя, мы могли бы сказать, что эта цель была достигнута, когда пользователь достиг пути URL:

/регистрация/полная

Итак, мы определяем a_b_goal_conditions_met:

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

Дорожки

Когда вы думаете о Paths в Django, естественно перейти к идее использования разных шаблонов. Есть ли другой способ, который еще предстоит изучить. При тестировании A/B вы делаете небольшие различия между двумя страницами и измеряете результаты. Поэтому лучше всего определить один базовый шаблон пути, из которого должны быть продолжены все пути к цели.

Как отображать эти шаблоны? Декоратор, вероятно, хороший старт - лучше всего в Django включить параметр template_name к вашим представлениям, который декоратор может изменить этот параметр во время выполнения.

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

Вы можете увидеть, как этот декоратор либо исследует завернутую функцию, либо модифицирует аргумент template_name, либо ищет правильные шаблоны где-то (например, Модель). Если бы мы не хотели добавлять декоратор к каждой функции, мы могли бы реализовать это как часть нашего ABMiddleware:

    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

Нам также нужно будет добавить способ отслеживания того, какие представления имеют тесты A/B и т.д.

Система для отправки зрителей по пути

В теории это легко, но есть много разных реализаций, поэтому не понятно, какой из них лучше. Мы знаем, что хорошая система должна равномерно распределять пользователей по пути. Необходимо использовать некоторый метод хеширования. Возможно, вы могли бы использовать модуль счетчика memcache, деленный на количество путей - возможно, есть лучший способ.

Система для записи результатов теста

Нам нужно записать, сколько пользователей пошло на какой-то Путь - нам также понадобится доступ к этой информации, когда пользователь достигнет цели (мы должны иметь возможность сказать, какой путь они достигли, чтобы соответствовать Условию цели ) - мы будем использовать какую-то модель для записи данных и Django Sessions или Cookies, чтобы сохранить информацию Path, пока пользователь не выполнит условие цели.

Заключительные мысли

Я дал много псевдо-кода для тестирования A/B в Django - выше это ни в коем случае не полное решение, а хорошее начало создания многоразовой структуры для тестирования A/B в Django.

Для справки вы можете посмотреть на Paul Mar Seven Minute A/Bs на GitHub - это версия ROR выше! http://github.com/paulmars/seven_minute_abs/tree/master


Обновление

При дальнейшем анализе и исследовании Оптимизатора веб-сайта Google очевидно, что в вышеприведенной логике есть щели. Используя различные шаблоны для представления Paths, вы разбиваете все кеширование в представлении (или если кэширование в представлении всегда будет служить одному и тому же пути!). Вместо этого, используя Paths, я вместо этого украл бы терминологию GWO и использовал идею Combinations - это одна конкретная часть изменения шаблона - например, изменение тега <h1> сайта.

Решение будет включать теги шаблонов, которые будут отображаться на JavaScript. Когда страница загружается в браузере, JavaScript делает запрос на ваш сервер, который извлекает одну из возможных комбинаций.

Таким образом, вы можете протестировать несколько комбинаций на странице при сохранении кеширования!


Обновление

По-прежнему есть место для переключения шаблонов - скажем, например, вы вводите совершенно новую домашнюю страницу и хотите проверить ее производительность на старой домашней странице - вы все равно хотите использовать технологию переключения шаблонов. Следует иметь в виду, что вам нужно найти способ переключения между X-кешированными версиями страницы. Для этого вам необходимо переопределить стандартное кэшированное промежуточное программное обеспечение, чтобы проверить, является ли это тест A/B на запрошенном URL-адресе. Затем он может выбрать правильную кешированную версию, чтобы показать!!!


Обновление

Используя описанные выше идеи, я применил подключаемое приложение для базового тестирования A/B Django. Вы можете получить его от Github:

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

Ответ 3

Если вы используете параметры GET, например, вы предложили (?ui=2), вам не нужно вообще прикасаться к urls.py. Ваш декоратор может проверить 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.

В качестве бонуса вы могли бы реорганизовать этот декоратор в будущем, если вы решите прекратить использование параметров GET и переместить что-то на основе файлов cookie и т.д.

Обновить Если у вас уже написано много просмотров, и вы не хотите их изменять, вы можете написать свою собственную версию 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})

Ответ 4

Ответ Justin правильный... Я рекомендую вам голосовать за него, как он был первым. Его подход особенно полезен, если у вас есть несколько видов, которые нуждаются в этой настройке A/B.

Обратите внимание, однако, что вам не нужен декоратор или изменения в urls.py, если у вас всего несколько представлений. Если вы оставили свой файл urls.py как...

(r'^foo/', my.view.here),

... вы можете использовать request.GET для определения запрошенного варианта просмотра:

def here(request):
    variant = request.GET.get('ui', some_default)

Если вы хотите избежать имен шаблонов жесткого кодирования для отдельных представлений A/B/C/etc, просто сделайте их конвенцией в схеме именования шаблонов (как рекомендует подход Justin):

def here(request):
    variant = request.GET.get('ui', some_default)
    template_name = 'heretemplates/page%s.html' % variant
    try:
        return render_to_response(template_name)
    except TemplateDoesNotExist:
        return render_to_response('oops.html')

Ответ 5

Код, основанный на одном: Джастин Восс:

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, то в случае индекса2 он перенаправляется на "? Ui = 33", в случае индекса 1 переменная пользовательского интерфейса устанавливается на 0.

Я использую 3 для перенаправления с главной страницы на Оптимизатор веб-сайта Google, который, в свою очередь, перенаправляет обратно на главную страницу с соответствующим параметром ui.

Ответ 6

Эти ответы кажутся устаревшими. В настоящее время Google Analytics, вероятно, является самым популярным и лучшим вариантом для большинства сайтов. Вот некоторые ресурсы для интеграции django с Google Analytics:

Плагины

Как Tos:

Ответ 7

Django-lean выглядит потрясающе. Я собираюсь попытаться это выяснить. Я закончил свое собственное решение, которого достаточно для того, что я пытался сделать. Я попытался скомпоновать его и упростить для новичков. Это супер базовый, попробуйте:

https://github.com/crobertsbmw/RobertsAB

Ответ 8

Я написал пример тестирования split для django, который может найти любой, кто может это найти, -

https://github.com/DanAncona/django-mini-lean

Любовь, чтобы услышать, что вы об этом думаете, и как я могу сделать ее более полезной!