alephbetでVueアプリをテストするA/B


本稿では、簡単なVueのためのA/Bテストをセットします.JSアプリとノードの実験を処理します.JSサーバー、SQLiteデータベースでそれらを保存します.
我々が始める前に、あなたがA/Bテストでリフレッシュを必要とするか、A/Bテストがユーザー・エクスペリエンスをドライブするためにNetflixによって使われる方法について学びたいならば、私はこれを推薦することができますseries on the Netflix tech blog .
この投稿のすべてのコードはGithub .

ゴール


アイデアは、クリックするだけでカウンタをインクリメントボタンを使用して簡単なカウンタアプリを構築することです.A/Bテストは、ユーザーが青ボタンまたは緑色のボタンを好むならば、テストすることができました.
ユーザーがボタンをクリックすると、イベントがノードサーバーにポストされます.これは、後の分析のための結果をデータベースに格納します.
設定は簡単ですが、それは比較的明確に関与原理を示す必要があります.

技術

  • 私たちは/Bのテストを実行するVue
  • ノード/Expressサーバの実験結果の処理
  • SQLiteデータベース実験結果の保存

  • AlephBet A/Bテストのためのフレームワーク
  • Vueプロジェクトの設定


    まず、基本的なVueプロジェクトを設定します.ここではVue 2を使用します.
    vue create client
    
    次に、いくつかの変更を行いますHelloWorld コンポーネントは、我々のテストの対象になります.VUEコンポーネントには、単一のボタンとカウンターがあります.The .is-blue and .is-green CSSクラスはA/Bテストのために後で使用されます.
    // client/src/components/HelloWorld.vue
    
    <template>
      <div class="hello">
        <p id="counter"> {{ counter }}</p>
        <button id="increment-btn" @click="increment">Increment</button>
      </div>
    </template>
    
    <script>
    export default {
      name: 'HelloWorld',
      data() {
        return {
          counter: 0,
        }
      },
      methods: {
        increment: function() {
          this.counter++;
        }
      }
    }
    </script>
    
    <style scoped>
    #counter {
      font-size: xxx-large;
    }
    
    #increment-btn {
      border: none;
      padding: 15px 32px;
      font-size: x-large;
      margin: 4px 2px;
      cursor: pointer;
    }
    
    .is-blue {
      background-color: #34495e;
      color: white;
    }
    
    .is-green {
      background-color: #41b883;
      color: white;
    }
    
    </style>
    

    Alephbetの設定


    前に述べたように、我々は使用されますAlephBet A/Bテストを管理する.

    構成


    まず、依存関係をインストールします.
    npm install alephbet
    
    次に、テストを構成できます.Vueプロジェクトで新しいファイルを設定するsrc/analytics/ab-testing.js .
    Alephbetをインポートした後、ラッパーメソッドを設定しますmakeExperiment 新しい実験を作成する.
    // client/src/analytics/ab-testing.js
    
    const AlephBet = require("alephbet");
    
    /**
     * Set up a new A/B testing experiment with AlephBet
     * @param name Name of the experiment
     * @param variants Object of the experiment variants
     * @param adapter Adapter of the experiment
     * */
    const makeExperiment = (name, variants, adapter) => {
        return new AlephBet.Experiment({
            name: name,
            variants: variants,
            tracking_adapter: adapter,
        });
    };
    
    alephbetsはデフォルトで実験アダプターとしてGoogle Analyticsを使用します.独自のバックエンドを設定したいので、カスタムアダプタが必要です.今のところ、我々は単にすべてのイベントをコンソールに記録します.
    // client/src/analytics/ab-testing.js
    
    /**
     * Wrapper for an A/B testing adapter for AlephBet experiments.
     * */
    const makeAdapter = () => {
        return {
            experiment_start: async function (experiment, variant) {
                console.log(experiment, variant, 'participate')
            },
            goal_complete: async function (experiment, variant, event_name) {
                console.log(experiment.name, variant, event_name)
            },
        };
    };
    

    バリアントの定義


    次に実験変種を定義できる.これらをJSオブジェクトに保存しますexperimentVariants キーは、実験の名前です.
    // client/src/analytics/ab-testing.js
    
    // Experiment variant presets
    const experimentVariants = {
        "button color": {
            green: {
                activate: function () {
                    document.getElementById("increment-btn").className = "is-green";
                },
                weight: 50,
            },
            blue: {
                activate: function () {
                    document.getElementById("increment-btn").className = "is-blue";
                },
                weight: 50,
            },
        },
    };
    
    内部のオブジェクトではblue and green . それぞれのバリアントはactivate AllPhbetによって呼び出される関数は、ユーザーのためにバリアントをアクティブにします.我々の場合はactivate 関数は.is-green or .is-blue インクリメントボタンへのCSSクラス.
    The weight ユーザーがバリアントを割り当てた可能性を指定します.
    最後に、2つのラッパーメソッドとオブジェクトをバリアントでエクスポートします.
    module.exports = {
        makeExperiment: makeExperiment,
        makeAdapter: makeAdapter,
        experimentVariants: experimentVariants,
    }
    

    Vueコンポーネントの設定


    実際の実験はHelloWorldコンポーネントで、特にmounted 成分の方法.
    Alephbetだけでなく、作成した関数をインポートして起動します.また、コンポーネントの最も外側のスコープでゴールの変数を定義する必要があります.
    // client/src/components/HelloWorld.vue
    
    import {
      experimentVariants,
      makeAdapter,
      makeExperiment,
    } from "@/analytics/ab-testing";
    import AlephBet from "alephbet";
    
    let goal;
    ...
    
    The goal 変数は、実験の目的の完了をキャプチャします.
    mounted 実験でゴールを設定する.セットunique: false 以来、すべてのクリックして登録されるだけでなく、最初のクリックします.
    // client/src/components/HelloWorld.vue
    
    ...
      mounted() {
        const name = "button color";
        const variants = experimentVariants[name];
        const adapter = makeAdapter();
        const experiment = makeExperiment(name, variants, adapter);
        goal = new AlephBet.Goal("button clicked", {unique: false});
        experiment.add_goal(goal);
      },
    ...
    
    最後に、ボタンがクリックされたときに実際にゴール補完を登録する必要があります.としてincrement 関数をクリックすると、そのメソッドに1行だけ追加できます.
    // client/src/components/HelloWorld.vue
    
    ...
    increment: function() {
          goal.complete()
          this.counter++;
        }
    ...
    
    これはクライアントの基本的な設定です.火災をあなたのアプリケーションを頭にlocalhost:8080 . これで、青色または緑色のインクリメントボタンを参照してください.Alephbetは、実際には1つのユーザーが常に同じバリアントを示すように、LocalStorage内のバリアントを格納します.したがって、他のバリアントを見たいなら、alephbet LocalStorageからのエントリーとページをリフレッシュします(あなたがランダムに他のグループに割り当てられるまで、何度かこれをしなければならないかもしれません).


    あなたがコンソールを開くならば、あなたはアダプターがすべてのゴール完成と同様に実験のスタートを記録することに気がつきます.
    リストの次に、我々の実験追跡サーバーの設定です.

    ノード。サーバーセットアップ


    2番目のディレクトリを設定するserver と同じレベルでclient Vueアプリ、セットアップNPMプロジェクトと依存関係をインストールします.
    mkdir server
    cd server
    npm init
    npm install express cors sqlite3
    

    インデックス.js


    次に、server 呼ばれるindex.js 次のコンテンツを追加します.
    // server/index.js
    
    const express = require("express")
    const app = express()
    const cors = require('cors')
    
    app.use(cors())
    
    // Server port
    const PORT = 5555;
    
    // Start server
    app.listen(PORT, () => {
        console.log(`Server running on port ${PORT}`)
    });
    
    // Root endpoint
    app.get("/", (req, res, next) => {
        res.json({"message":"Ok"})
    });
    
    // A/B testing endpoint
    app.post("/track_experiment", (req, res) => {
        const experiment = req.query.experiment;
        const variant = req.query.variant;
        const event = req.query.event;
    
        if (experiment === null || variant === null || event === null) {
            res.status(400);
            return;
        }
    
        console.log(experiment, variant, event);
        res.json({"message":"Ok"})
    })
    
    // 404 not found for other requests
    app.use(function(req, res){
        res.status(404);
    });
    
    ここでは詳細は説明しませんが、基本的にはポート5555で動作するシンプルなサーバを設定しています/track_experiment エンドポイント、我々は我々の実験のイベントを送信することができますカウンタアプリから.

    データベース.js


    実験結果を永続的に保存するために,sqliteデータベースを使用した.ここでのセットアップは非常に基本的であり、可能性があります改善されるが、この概念の証拠には十分である.
    server ディレクトリを作成するdatabase.js :
    // server/database.js
    
    const sqlite3 = require('sqlite3').verbose()
    
    const DB_FILE = "db.sqlite"
    
    let db = new sqlite3.Database(DB_FILE, (error) => {
        if (error) {
            // Error opening db
            console.error(error.message)
            throw error
        }
        else{
            console.log('Connected to the SQLite database.')
    
            const sql = `
            CREATE TABLE experiment (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name text, 
                variant text, 
                event text
                );
            `
            db.run(sql, (err) => {/* table already exists */});
        }
    });
    
    module.exports = db
    
    これは1つのテーブルをセットアップするexperiment カラムでid , name , variant , and event .
    データベースを設定したので、APIエンドポイントの残りを埋めることができます.

    インデックスへ.js


    まず、インポートdb ファイルの開始時にオブジェクトを返します.
    // server/index.js
    ...
    const db = require("./database.js")
    ...
    
    我々は現在更新することができます/track_experiment 受信した実験データをデータベースに挿入します.最終エンドポイントはこのようになります.
    // server/index.js
    
    ...
    
    // A/B testing endpoint
    app.post("/track_experiment", (req, res) => {
        const experiment = req.query.experiment;
        const variant = req.query.variant;
        const event = req.query.event;
    
        if (experiment === null || variant === null || event === null) {
            res.status(400);
            return;
        }
    
        // Insert into database
        const sql = 'INSERT INTO experiment (name, variant, event) VALUES (?, ?, ?)'
        const params = [experiment, variant, event];
    
        db.run(sql, params, function (error, result) {
            if (error){
                res.status(400).json({"error": error.message})
                return;
            }
            res.json({
                "message": "success",
                "data": params,
                "id" : this.lastID
            })
        })
    })
    
    ...
    
    我々は、サーバーを起動してこれを試してみることができますnode server/index.js そして、curlを使ってエンドポイントにテストリクエストを送信する.
    curl --request POST "http://localhost:5555/track_experiment?experiment=myname&variant=myvariant&event=myevent"
    
    > {"message":"success","data":["myname","myvariant","myevent"],"id":1}%  
    
    成功!

    Vueアプリをサーバーと統合する


    サーバーとDBを実行しているので、我々は現在、サーバーにクライアントを接続することができます.
    頭に戻るclient ディレクトリ.編集しますab-testing.js ファイル.
    まず、イベントを追跡サーバーに投稿するメソッドを追加する必要があります.
    // client/src/analytics/ab-testing.js
    
    /**
     * Post an experiment result to the tracking server.
     * */
    const postResult = (experiment, variant, event) => {
        let URL = "http://localhost:5555/track_experiment"
        URL += `?experiment=${experiment}&variant=${variant}&event=${event}`
        fetch(URL, {
            method: 'POST'
        }).catch(console.error)
    }
    
    ほとんど完了.さて、makeAdapter ラッパー関数この新しいメソッドを使用します.次のコードを更新します.
    // client/src/analytics/ab-testing.js
    
    ...
    
    const makeAdapter = () => {
        return {
            experiment_start: async function (experiment, variant) {
                postResult(experiment.name, variant, 'participate')
            },
            goal_complete: async function (experiment, variant, event_name) {
                postResult(experiment.name, variant, event_name)
            },
        };
    };
    
    ...
    
    それです.任意の実験結果がサーバーに投稿され、データベースに保存されます.

    最後の思考


    Alephbetによる基本的なA/B試験の設定はロケット科学ではないこのデモプロジェクトはかなり簡単ですが、それはまともな導入として機能します.
    フィードバックを得るために無料でお気軽に!
    ハッピーA/Bテスト🎉