DEV Community

Cover image for Running non-blocking A/B tests, feature flags with Laravel, PHP
Alex Yatsenko
Alex Yatsenko

Posted on

Running non-blocking A/B tests, feature flags with Laravel, PHP

Illustration of nothing

Hey guys. My name is Alex. I'm a software engineer in unicorn by day and the founder of a couple of SaaS projects by night (and evening sometimes). From Ukraine, now living in Porto.

Author photo

Introduction

This story is about the ABRouter - new open-source platform for running A/B tests, feature flags, and collecting statistics on the back-end side with the high level of support of Laravel, PHP, and Symfony.

Additionally, that tool supports Parallel Running - built-in mode that allows using the features in non-blocking mode. All that you need to do - is configure the queues and Redis on your project. Unfortunately, this mode is not supported for Symfony now, but you can help us implement it (because the tool is open-source).

As I said, the tool is fully open-source, and I have almost nothing to sell, except for the cloud version, hah :)

Our first task with A/B test

So, I propose to start implementing first A/B test with a simple example - testing the most convertible color of the checkout button. For example, your current color of the sign-up button is blue, but you want to check, what if the green button will be more convertible?

Goal: To test the most convertible color of the form button
Branches distribution: red - 33%, green - 33%, blue - 33%.
Technical task: assign the color of the button: which the user got into.

Creating the first A/B test on the ABR side

Step 1

Sign-up by the link

Please, note you can deploy ABRouter locally or on your remote server.
learn more about deploying

Step 2

Create your experiment

Pay attention to the Experiment ID. You will use it as the identifier of the experiment to run it.

Create experiment

Step 3

Grab the data
After creating the A/B test you can get the important data to run it.
Experiment id:
Grab Experiment id:

Token:
Grab token

Configure application side

If you're using Laravel:

Install the library to your codebase on PHP:https://github.com/abrouter/laravel-abtest

This library is based on the main ABRouter client:https://github.com/abrouter/abrouter-php-client

composer requires abrouter/laravel-abtest

This package provides auto-discovery for the service provider. If Laravel package auto-discovery is disabled, add service providers manually in your /app/app.php of your repository.
There are service providers you must add:
\Abrouter\LaravelClient\Providers\AbrouterServiceProvider::class

Publish client configuration:
php artisan vendor:publish --tag=abrouter

Configure the client:

<?php
declare(strict_types = 1);

return [
    'token' => '0ea94e3527644b8e6259b790d866223490f3c91634bbfd0eb978b4a57a4d835d57ab5195f892b15d',
    'host' => 'https://abrouter.com',
];

Enter fullscreen mode Exit fullscreen mode

If you're using vanilla PHP:

composer require abrouter/abrouter-php-client

abrouter/abrouter-php-client repository on Github

Please, visit the repository for configuration instructions. The package wouldn't work without DI. So, if you're not using DI yet, try PHP-DI.

If you're using Symfony:

Install the library to your codebase on PHP:

https://github.com/abrouter/symfony-abtest

composer require abrouter/symfony-abtest

Register the bundle:

// config/bundles.php
return [
// [...]
Abrouter\SymfonyClient\AbrouterClientBundle::class => ['all' => true],
];
Enter fullscreen mode Exit fullscreen mode

Put your ABRouter token in /config/packages/abrouter_client.yaml

abrouter_client:
  token:                ''
  host:                 'https://abrouter.com'
Enter fullscreen mode Exit fullscreen mode

Common recommendations

Feel free to learn additional details in the repositories of framework you're using. If you want to configure Parallel(non-blocking) running please read package instructions.

Start coding A/B test

If you're using Laravel:

<?php

use Abrouter\Client\Builders\StatEventBuilder;
use Abrouter\Client\Client;

class ExampleController
{
    public function __invoke(Client $client, StatEventBuilder $statEventBuilder)
    {
        $userId = auth()->user()->id;
        $buttonColor = $client->experiments()->run($userId, 'button_color_test');

        //send the statistics
        $client->statistics()->sendEvent(
            $eventBuilder
                ->incremental()
                ->event('button_test_visit')
                ->setUserId($userId)
                ->build()
        );


        return view('button', [
            'color' => $buttonColor->getBranchId(),
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

Additionally, check out the example for Laravel https://github.com/abrouter/laravel-example

If you're using vanilla PHP:

<?php

use Abrouter\Client\Config\Config;
use DI\ContainerBuilder;
use Abrouter\Client\Client;

require '/app/vendor/autoload.php';

$containerBuilder = new ContainerBuilder();
$di = $containerBuilder->build();

$token = '04890788ba2c89c4ff21668c60838a00a87b1cf42c9c6b45d6aa8e11174f0d5762b16b6c09b6b822'; //you can find your token in ABRouter dashboard

$di->set(Config::class, new Config($token, 'https://abrouter.com'));
/**
 * @var Client $client
 */
$client = $di->make(Abrouter\Client\Client::class);

$statBuilder = $di->make(Abrouter\Client\Builders\StatEventBuilder);

$userSignature = $_SESSION['user_id'] ?? uniqid();
$experimentId = 'button_color_test';//experiment id is also there


$runExperimentResult = $client->experiments()->run($userSignature, $experimentId);

//sending button_test_page_visit event as button_test_page_visit+1
$client->statistics()->sendEvent(
     $eventBuilder
        ->incremental()
        ->event('button_test_visit')
        ->setUserId($userId)
        ->build()
);


$experimentId = $runExperimentResult->getExperimentId(); //form-color
$branchId = $runExperimentResult->getBranchId(); //red
echo '<button style="color: '. $branchId .'">Hello</button>';
Enter fullscreen mode Exit fullscreen mode

If you're using Symfony:

<?php

namespace App\Controller;

use Abrouter\Client\Client;
use Abrouter\Client\Manager\ExperimentManager;
use Symfony\Component\HttpFoundation\Response;
use Abrouter\Client\Builders\StatEventBuilder;

class IndexController
{
    public function index(Client $client, StatEventBuilder $statBuilder)
    {
        $userId = $this->getUser()->getUsername();

        //sending button_test_page_visit event as button_test_page_visit+1
        $client->statistics()->sendEvent(
             $eventBuilder
                ->incremental()
                ->event('button_test_visit')
                ->setUserId($userId)
                ->build()
         );


        /**
         * The button color will be changed 50% green/50% red
         */
        $buttonColorExperimentId = 'button_color_test';
        return new Response(json_encode([
            'button_color' => $client
                ->experiments()
                ->run($userId, $buttonColorExperimentId)->getBranchId(),
        ]));
    }
}
Enter fullscreen mode Exit fullscreen mode

Additionally, check out the example for symfony https://github.com/abrouter/symfony-abtest-example

Results variations of A/B test

Color of the button will be automatically changed on each request for every page reload. Because we have used uniqid(). ABRouter system will memorize the relation between user identifier and branch he got, so if we will repeat the request with the same user identifier we will get the same branch as on previous run.

Results of A/B testing

Tracking

Feel free to send the statistics to the ABRouter server. The product support showing statistics by experiment and over all. Learn more about the statistics in the docs.

Running feature flag example

Running feature flag is a kind common for all platforms. Let's see how to do it with Laravel:

<?php
declare(strict_types = 1);

namespace App\Http\Controllers;

use Abrouter\Client\Client;

class ExampleFeatureFlagsController
{
    public function __invoke(Client $client)
    {
        $enabledButtonFeatureFlag = $client->featureFlags()
            ->run('enabled_button_feature_flag');
        $disabledButtonFeatureFlag = $client->featureFlags()
            ->run('disabled_button_feature_flag');

        return view(
          'featureFlags',
          [
            'enabledButtonFeatureFlag' => $enabledButtonFeatureFlag,
            'disabledButtonFeatureFlag' => $disabledButtonFeatureFlag,
          ]
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Useful links

Deploy ABRouter locally or on the remote server
Running feature flags
Laravel client GitHub - includes full instructions for running on Laravel
PHP client GitHub - includes full instructions for running on PHP
Symfony client GitHub - includes full instructions for running on PHP
ABRouter website

Summary

I have shown you how to implement an A/B test, feature flags and send the statistics with Laravel, Symfony and PHP via ABRouter. Looks like it's quite simple.
Please, remember, that every change that you are making to the app should be through an A/B test. It's a key to build a successful product.

If you have any questions, feel free to ask me at abrouter@proxiedmail.com

Thank you for reading.

Discussion (0)