Tips & Tricks

How to Implement A/B Testing with Claude Code

Learn how to implement a/b testing using Claude Code. Includes practical code examples and step-by-step guidance.

A/Bテスト実装の全体像

A/Bテストはデータに基づく意思決定に不可欠です。しかし、正しい統計処理やユーザー振り分け、結果の追跡まで自前で実装するのは大変です。Claude Codeを使えば、統計的に正しいA/Bテスト基盤を効率よく構築できます。

テスト振り分けエンジン

> ユーザーを一貫してA/Bグループに振り分けるエンジンを作って。
> 同じユーザーには常に同じバリアントを返すようにして。
import crypto from 'crypto';

interface Experiment {
  id: string;
  variants: { id: string; weight: number }[];
}

class ABTestEngine {
  private experiments: Map<string, Experiment> = new Map();

  register(experiment: Experiment) {
    const totalWeight = experiment.variants.reduce((sum, v) => sum + v.weight, 0);
    if (Math.abs(totalWeight - 100) > 0.01) {
      throw new Error('バリアントの重みの合計は100にしてください');
    }
    this.experiments.set(experiment.id, experiment);
  }

  assign(experimentId: string, userId: string): string {
    const experiment = this.experiments.get(experimentId);
    if (!experiment) throw new Error(`実験が見つかりません: ${experimentId}`);

    const hash = crypto
      .createHash('md5')
      .update(`${experimentId}:${userId}`)
      .digest('hex');
    const bucket = parseInt(hash.substring(0, 8), 16) % 100;

    let cumulative = 0;
    for (const variant of experiment.variants) {
      cumulative += variant.weight;
      if (bucket < cumulative) return variant.id;
    }
    return experiment.variants[0].id;
  }
}

// Usage example
const engine = new ABTestEngine();
engine.register({
  id: 'checkout-flow',
  variants: [
    { id: 'control', weight: 50 },
    { id: 'new-design', weight: 50 },
  ],
});

Reactコンポーネントでの利用

import { createContext, useContext, useEffect } from 'react';

function useExperiment(experimentId: string): string {
  const engine = useContext(ABTestContext);
  const userId = useCurrentUserId();
  const variant = engine.assign(experimentId, userId);

  useEffect(() => {
    trackEvent('experiment_exposure', {
      experimentId,
      variant,
      userId,
    });
  }, [experimentId, variant, userId]);

  return variant;
}

// コンポーネントでの使用
function CheckoutPage() {
  const variant = useExperiment('checkout-flow');

  return variant === 'new-design'
    ? <NewCheckoutFlow />
    : <CurrentCheckoutFlow />;
}

結果の統計分析

A/Bテストの結果を正しく評価するために、統計的有意差の計算が必要です。

interface TestResult {
  sampleSize: number;
  conversions: number;
}

function calculateSignificance(control: TestResult, treatment: TestResult) {
  const p1 = control.conversions / control.sampleSize;
  const p2 = treatment.conversions / treatment.sampleSize;

  const pooledP = (control.conversions + treatment.conversions) /
    (control.sampleSize + treatment.sampleSize);

  const se = Math.sqrt(
    pooledP * (1 - pooledP) * (1 / control.sampleSize + 1 / treatment.sampleSize)
  );

  const zScore = (p2 - p1) / se;
  const pValue = 2 * (1 - normalCDF(Math.abs(zScore)));

  return {
    controlRate: (p1 * 100).toFixed(2) + '%',
    treatmentRate: (p2 * 100).toFixed(2) + '%',
    improvement: (((p2 - p1) / p1) * 100).toFixed(2) + '%',
    pValue: pValue.toFixed(4),
    significant: pValue < 0.05,
  };
}

function normalCDF(x: number): number {
  const a1 = 0.254829592, a2 = -0.284496736;
  const a3 = 1.421413741, a4 = -1.453152027;
  const a5 = 1.061405429, p = 0.3275911;
  const sign = x < 0 ? -1 : 1;
  x = Math.abs(x) / Math.sqrt(2);
  const t = 1.0 / (1.0 + p * x);
  const y = 1.0 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
  return 0.5 * (1.0 + sign * y);
}

Summary

Claude Codeを使えば、ユーザー振り分けから統計的有意差の計算まで、A/Bテスト基盤を一貫して構築できます。フィーチャーフラグとの連携はフィーチャーフラグ実装を、アナリティクス連携はアナリティクス実装ガイドを参照してください。

統計的検定の理論についてはEvan Miller - Sample Size Calculatorが参考になります。

#Claude Code #A/B testing #analytics #React #statistics