es útil para dar un paso atrás y abstracto lo que a/Testin B g está tratando de hacer antes de sumergirse en el código. ¿Qué es exactamente lo que necesitamos para realizar una prueba?
- un objetivo que tiene una condición
- Al menos dos caminos distintos para satisfacer la condición del Meta
- Un sistema para el envío de los espectadores por una de las rutas de acceso
- Un sistema para registrar los resultados de la prueba
Con esto en mente, pensemos en la implementación.
El objetivo
Cuando pensamos en una meta en la web por lo general nos referimos a que un usuario llega a una determinada página o que se complete una acción específica, por ejemplo, registrarse con éxito como un usuario o para llegar a la página de pago
En Django podríamos modelar que en un par de maneras - tal vez ingenuamente, dentro de un punto de vista, llamar a una función cada vez que un objetivo ha sido alcanzado:
def checkout(request):
a_b_goal_complete(request)
...
Pero eso no ayuda porque tendremos para agregar ese código en cualquier lugar que lo necesitemos; además, si utilizamos cualquier aplicación conectable, preferimos no editar su código para agregar nuestra prueba A/B.
¿Cómo podemos introducir Metas A/B sin editar directamente el código de vista? ¿Qué tal un Middleware?
class ABMiddleware:
def process_request(self, request):
if a_b_goal_conditions_met(request):
a_b_goal_complete(request)
Eso nos permitiría rastrear las Metas A/B en cualquier parte del sitio.
¿Cómo sabemos que se cumplen las condiciones de un objetivo? Para facilitar la implementación, sugeriré que sepamos que un objetivo ha cumplido sus condiciones cuando un usuario llega a una ruta de URL específica. Como beneficio adicional podemos medir esto sin ensuciarnos las manos dentro de una vista. Para volver a nuestro ejemplo de registro de un usuario que podríamos decir que este objetivo se ha cumplido cuando el usuario llega a la ruta URL:
/registro/completa
Así definimos a_b_goal_conditions_met
:
a_b_goal_conditions_met(request):
return request.path == "/registration/complete":
Caminos
al pensar en caminos en Django que es natural para saltar a la idea de utilizar diferentes plantillas. Si queda otro camino por explorar. En las pruebas A/B, usted hace pequeñas diferencias entre dos páginas y mide los resultados. Por lo tanto, debe ser una mejor práctica definir una única plantilla de ruta base a partir de la cual deben extenderse todas las rutas a la meta.
¿Cómo deberían renderizarse estas plantillas? Un decorador es probablemente un buen comienzo. Es una buena práctica en Django incluir un parámetro template_name
en sus vistas. Un decorador podría alterar este parámetro en tiempo de ejecución.
@a_b
def registration(request, extra_context=None, template_name="reg/reg.html"):
...
se podía ver este decorador ya sea introspección de la función envuelta y modificar el argumento template_name
o mirando las plantillas correctas de algún lugar (como un modelo).Si no queríamos añadir el decorador a todas las funciones que podríamos aplicar esto como parte de nuestra 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
Necesitaríamos también tenemos que añadir un poco de manera de no perder de los cuales tienen vistas A/B las pruebas se ejecutan etc.
un sistema para el envío de los espectadores por un camino
En teoría esto es fácil, pero hay gran cantidad de diferentes implementaciones de modo que no está claro cuál es el mejor. Sabemos que un buen sistema debe dividir a los usuarios de manera uniforme en el camino. Se debe usar algún método hash. Quizás se pueda usar el módulo del contador de Memcache dividido por el número de Rutas. Tal vez haya una mejor manera.
Un sistema de registro de los resultados de la prueba
necesitamos registrar el número de usuarios descendieron lo Path - también necesitaremos acceso a esta información cuando el usuario llega a la meta (necesitamos ser capaz de decir qué camino bajaron para cumplir con la Condición de la Meta) - usaremos algún tipo de Modelo (s) para registrar los datos y las Sesiones de Django o las Cookies para conservar la información de la Ruta hasta que el usuario cumpla con la Meta condición.
Pensamientos finales
me he dado un montón de pseudo código para la implementación de las pruebas A/B en Django - lo anterior es de ninguna manera una solución completa, pero un buen comienzo hacia la creación de un marco reutilizable para una/B de prueba en Django.
Como referencia, puede consultar los 7 minutos de duración de Paul Mar en GitHub: ¡es la versión ROR de los anteriores! http://github.com/paulmars/seven_minute_abs/tree/master
actualización
En una posterior reflexión e investigación de Google Website Optimizer es evidente que hay agujeros en la lógica anterior. Al usar diferentes plantillas para representar Rutas, se rompe todo el almacenamiento en caché en la vista (o si la vista se almacena en caché, ¡siempre servirá la misma ruta!). En lugar de usar Paths, en cambio, robaría la terminología de GWO y usaría la idea de Combinations
, que es una parte específica de un cambio de plantilla, por ejemplo, cambiar la etiqueta <h1>
de un sitio.
La solución implicaría etiquetas de plantilla que se procesarían en JavaScript. Cuando la página se carga en el navegador, JavaScript hace una solicitud a su servidor que busca una de las posibles combinaciones.
¡De esta forma puede probar múltiples combinaciones por página mientras preserva el almacenamiento en caché!
actualización
Todavía hay espacio para la plantilla de conmutación - dice, por ejemplo, se introduce una nueva página de inicio, y quiere comprobar su rendimiento frente a la antigua página de inicio - que todavía querrá usar la técnica de cambio de plantilla. Lo que hay que tener en cuenta es que tendrá que encontrar la manera de cambiar entre las X versiones de la página en caché. Para hacerlo, debe sobrescribir el middleware en caché estándar para ver si se trata de una prueba A/B que se ejecuta en la URL solicitada.¡Entonces podría elegir la versión correcta en caché para mostrar!
actualización
Usando las ideas descritas anteriormente he implementado una aplicación enchufable para pruebas básicas de A/B Django. Se puede bajar de él Github:
http://github.com/johnboxall/django-ab/tree/master
Pero esto implica la modificación de todos los puntos de vista anteriores existant ¿verdad? No quiero hacer eso. ¿Hay alguna manera alternativa de que mi antiguo código permanezca igual y esta prueba de ab se mantenga al margen? –
Podría escribir su propia versión de render_to_response, supongo, que interactuaría con este decorador para lograr lo que desea. Agregaré una muestra de código a mi respuesta para demostrar. –
Justin: sus dos sugerencias son excelentes. Maddy: si quieres probar A/B en un sitio completo, entonces no, vas a tener que morder la bala en algún lugar de tu cadena de solicitud/respuesta y, de forma programática o declarativa, indicar qué plantillas coinciden con los números 'ui'. –