Skip to content
This repository has been archived by the owner on Jan 16, 2019. It is now read-only.

Docs MVC Variant

Frank Kleine edited this page Apr 7, 2012 · 1 revision

Table of Contents

Testing customer experience with variants

When operating a website from time to time questions arise like "Would more customers order product B if we change some buttons or texts?". To test this often you need to run the version in a certain time frame, measure the performance (e.g. with a conversion rate), then do the changes and deploy them and run the new version for the same amount of time to get comparable results. However mostly on commercial sites there is a lack of time to run both versions one after another. Another use case could be displaying a special offer for users that come to your site with a certain request parameter. You must be able to notify the user about the special offer, but other visitors that did not come to your site with the special request parameter should not take any notice of the special offer.

The solution is to use a variant system that allows you to run different versions of the site at the same time, without an increasing amount of maintenance required. Stubbles contains a feature called variant manager that allows you to define several variants of your site, and to ask for the current valid variant within the pages to display content dependent of the selected variant.

How does it work?

On a first request by a user the variant manager reads the configuration and builds a variant tree from it. A leaf in the variant tree is a concrete variant. Variants may have an unrestricted number of children. After the variant tree has been created, the variant selection algorithm dives into the tree and asks every variant if it is valid. If it is not valid, the algorithm checks the next leaf on the same level. If a valid variant is found its children are checked. If any of the children is valid, the first valid child will be selected, else the variant itself will be selected. The selected variant will be stored in the session, so any subsequent requests of the same user will yield the same variant and no new selection will be done.

Summarized: For a new visitor the first valid variant will be selected.

To ensure that a user will get the same variant on a new visit the name of the variant is stored within a cookie. For a returning user it will be checked if the variant is still available. If it is not, a new variant will be selected depending on the configuration. If the variant is still available, the variant selection algorithm checks if there is any valid enforcing variant. Enforcing means that a variant will be selected over a variant from a cookie. A useful example for this behaviour could be a user that was on our site where he got a certain variant. Some days later he returns via a link containing a special request parameter that triggers the display of a special offer. Now the user will get the variant with this offer, not the old variant from his last visit. However if there is no enforcing variant the user will retain is variant from the last visit.

Summarized: For a returning visitor the old variant will be selected if it is still available and if there is no enforcing variant. If there are enforcing variants the first enforcing variant will be selected. The returning visitor will get a complete new variant just like a new visitor if the old variant is not available any more.

However, when changing the variant configuration sometimes old variants stay, but you want to have a new decision which variant the user should see. This is useful when starting variant tests, where you still have the old variant and add another one. To enforce selection of a new variant even if the user has a variant cookie simply change the name of the variant configuration. Beside the variant name the user has a variant configuration name cookie. If the value of variant configuration name cookie and the variant configuration name do not match the variant cookie is not evaluated.

Variant types

Stubbles delivers three different variant types: net::stubbles::websites::variantmanager::types::stubLeadVariant, net::stubbles::websites::variantmanager::types::stubRandomVariant and net::stubbles::websites::variantmanager::types::stubRequestParamVariant.

Lead variants

Lead variants are always valid, but never enforcing.

Random variants

Random variants have a certain weight. If two random variants are configured on the same level, i.e. if they are siblings within a variant tree, and both random variants have a weight of 1, then the chance that one the variants is chosen is 50%. Another example: If variant A has a weight of 1 and variant B has a weight of 2, then the chance that variant A is selected is 33% and the chance that variant B is selected is 66%. Random variants are never enforcing.

RequestParam variants

A request param variant depends on a request parameter set in the request. If the variant is configured for a request parameter called "example" the variant will not be valid if no request parameter with this name is set. A request param variant can be configured to be valid if the parameter is set, but can be restricted to a certain value of the parameter, too. This means there could be two request param variants, on that is valid if the value of "example" is "hello" and another one which is valid if the value of "example" is "world". A request param variant is enforcing when it is valid.

Create your own variant type

It is possible to create your own variant type. To do this, you just need to extend net::stubbles::websites::variantmanager::types::stubAbstractVariant (or implement the net::stubbles::websites::variantmanager::types::stubVariant interface by yourself). The most important methods are isEnforcing() and isValid(). Both return a boolean value and determine if the variant is selected or not.

A variant should return true on isEnforcing() if the variant MUST be selected. The first variant returning true on isEnforcing() will be selected, any subsequent variants will not be checked anymore (except for children variants of the enforcing variant). Enforcing variants that are valid will overwrite a variant that was stored in a cookie of the user.

A variant should return false on isValid() if the variant MUST NOT be selected. A variant returing false on isValid() and all its children will not be considered in the variant selection process.

XSL-templates to check for variants

See Variant support in XML/XSL view engine.

Configuring the variant manager

Configuring the variant tree

This section applies when you are using the default variant factory supplied by Stubbles (see below for more informations about variant factories).

Applies to Stubbles 1.6.0 or greater

Variants are configured inside the config/variantmanager.xml file. It could look like this:

#xml
<?xml version="1.0" encoding="utf-8"?>
<variants name="default">
  <requestParam name="request" title="request" paramName="var" />
  <random name="random1" title="random1" weight="1">
    <lead name="lead" title="lead" />
  </random>
  <random name="random2" title="random2" weight="2" />
</variants>

Applies to Stubbles 1.5.x or lower

Variants are configured inside the config/xml/variantmanager.xml file. It could look like this:

#xml
<?xml version="1.0" encoding="utf-8"?>
<xj:configuration
    xmlns:xj="http://xjconf.net/XJConf"
    xmlns="http://stubbles.net/websites/variantmanager">
  <variants name="default">
    <requestParam name="request" title="request" paramName="var" />
    <random name="random1" title="random1" weight="1">
      <lead name="lead" title="lead" />
    </random>
    <random name="random2" title="random2" weight="2" />
  </variants>
</xj:configuration>

The xj:configuration is not of interest for us. The real story starts at the variants tag. This tag denotes the variant tree, all variants must be inside this tag. Each variant type has its own tag: requestParam denotes a RequestParam variant, random denotes a random variant and lead denotes a lead variant (see above for the meaning of the single variant types). What we have in this example are three variants on the root level: a request param variant called request, a random variant called random1, and another random variant called random2. Please note that the order of the variant is important for the variant selection algorithm. If the request param variant would be last it would never be used even if the request parameter var is present, because the random variants will be valid and one of those would be selected before the request param variant could be asked if it is valid.

What will be the results of a variant selection? If the request parameter var is set, the variant calles request would be selected. If it is not present, the selection would choose randomly between random1 and random2, while random2 would be picked twice as much as random1 because its weight is twice as much as the weight of random1.

Tags for your own variant types

Applies to Stubbles 1.6.0 or greater

If you created your own variant type (see above for how to do this) you can put a definition file called variantmanager.ini into src/main/resources/variantmanager. The variant factory will read this file and provide the possibility to use the choosen tag in your variant manager configuration file. The definition file must look like this:

[example]
class="my::exampleapp::ExampleVariant"
param1=required
param2=optional

With this you can now configure your ExampleVariant in the config file:

#xml
<?xml version="1.0" encoding="utf-8"?>
<variants name="default">
  <example name="foo" title="request" param1="value"/>
  <example name="bar" title="request" param1="other" param2="more"/>
</variants>

Of course the ExampleVariant can have child variants, too.

Please note that this only allows having configuration values as attributes. There is no possibility to define child tags for configuration purposes.

Applies to Stubbles 1.5.x or lower

If you created your own variant type (see above for how to do this) you can put a definition file called variantmanager.xml into src/main/resources/xjconf. The variant factory will read this file and provide the possibility to use the choosen tag in your variant manager configuration file. See XJConf for information about creating XJConf definition files.

Enabling the variant manager

The variant manager package contains a pre interceptor class named net::stubbles::websites::variantmanager::stubVariantsPreInterceptor. If this class is configured within the MVC component's pre interceptor list the variant manager will start working. See Configuring Interceptors for how to do this.

Applies to Stubbles 1.(3|4).3 and greater To be able to switch between different variants during developments the stage assistant offers a variant selector. To make it work properly you need to add the net::stubbles::websites::variantmanager::stubVariantSwitchPreInterceptor as pre interceptor.

Variant factories

Variant factories create the variant tree.

Applies to Stubbles 1.6.0 or greater

 Stubbles itself delivers a <tt>net::stubbles::websites::variantmanager::stubXmlVariantFactory</tt> that builds the variant tree from a xml configuration file.

Applies to Stubbles 1.5.x or lower

 Stubbles itself delivers a <tt>net::stubbles::websites::variantmanager::stubVariantXJConfFactory</tt> that builds the variant tree from a xml configuration file.

You may create your own variant factory to build the variant tree from any other source you like (e.g. from a database). To achieve this simply extend the net::stubbles::websites::variantmanager::stubAbstractVariantFactory (or implement the net::stubbles::websites::variantmanager::stubVariantFactory interface). The important work is to create the net::stubbles::websites::variantmanager::stubVariantsMap instance and add variants to it.

If you use the variant manager pre interceptor you can configure it to use your own variant factory by adding a binding during application setup. This will overrule the implicit binding from within the framework.

Clone this wiki locally